#include "libopenim.h"
#include "ohos_utils/napi_handler.h"

#define USER_DATA(h, handler) h.userData = (void *)handler
#define NAPI_HANDLER_CHECK_GET(napiHandler, userData)                \
    LOGD("enter");                                                   \
    LOGD("userData: %p", userData);                                  \
    NapiHandler *napiHandler = static_cast<NapiHandler *>(userData); \
    if (napiHandler == nullptr) {                                    \
        LOGE("handler is nullptr in %s", __func__);                  \
        return;                                                      \
    }

static napi_ref ParseOnSuccessFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnSuccessFn(napi_env env, const OnSuccessFn &value)
{
    return nullptr;
}

static napi_ref ParseOnErrorFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnErrorFn(napi_env env, const OnErrorFn &value)
{
    return nullptr;
}

static napi_ref ParseOnSendProgressFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnProgressFn(napi_env env, const OnProgressFn &value)
{
    return nullptr;
}

static napi_ref ParseOnConnectingFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnConnectingFn(napi_env env, const OnConnectingFn &value)
{
    return nullptr;
}

static napi_ref ParseOnConnectSuccessFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnConnectSuccessFn(napi_env env, const OnConnectSuccessFn &value)
{
    return nullptr;
}

static napi_ref ParseOnConnectFailedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnConnectFailedFn(napi_env env, const OnConnectFailedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnKickedOfflineFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnKickedOfflineFn(napi_env env, const OnKickedOfflineFn &value)
{
    return nullptr;
}

static napi_ref ParseOnUserTokenExpiredFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnUserTokenExpiredFn(napi_env env, const OnUserTokenExpiredFn &value)
{
    return nullptr;
}

static napi_ref ParseOnUserTokenInvalidFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnUserTokenInvalidFn(napi_env env, const OnUserTokenInvalidFn &value)
{
    return nullptr;
}

static napi_ref ParseOnJoinedGroupAddedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnJoinedGroupAddedFn(napi_env env, const OnJoinedGroupAddedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnJoinedGroupDeletedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnJoinedGroupDeletedFn(napi_env env, const OnJoinedGroupDeletedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnGroupMemberAddedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnGroupMemberAddedFn(napi_env env, const OnGroupMemberAddedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnGroupMemberDeletedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnGroupMemberDeletedFn(napi_env env, const OnGroupMemberDeletedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnGroupApplicationAddedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnGroupApplicationAddedFn(napi_env env, const OnGroupApplicationAddedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnGroupApplicationDeletedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnGroupApplicationDeletedFn(napi_env env, const OnGroupApplicationDeletedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnGroupInfoChangedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnGroupInfoChangedFn(napi_env env, const OnGroupInfoChangedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnGroupDismissedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnGroupDismissedFn(napi_env env, const OnGroupDismissedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnGroupMemberInfoChangedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnGroupMemberInfoChangedFn(napi_env env, const OnGroupMemberInfoChangedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnGroupApplicationAcceptedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnGroupApplicationAcceptedFn(napi_env env, const OnGroupApplicationAcceptedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnGroupApplicationRejectedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnGroupApplicationRejectedFn(napi_env env, const OnGroupApplicationRejectedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnSyncServerStartFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnSyncServerStartFn(napi_env env, const OnSyncServerStartFn &value)
{
    return nullptr;
}

static napi_ref ParseOnSyncServerFinishFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnSyncServerFinishFn(napi_env env, const OnSyncServerFinishFn &value)
{
    return nullptr;
}

static napi_ref ParseOnSyncServerProgressFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnSyncServerProgressFn(napi_env env, const OnSyncServerProgressFn &value)
{
    return nullptr;
}

static napi_ref ParseOnSyncServerFailedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnSyncServerFailedFn(napi_env env, const OnSyncServerFailedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnNewConversationFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnNewConversationFn(napi_env env, const OnNewConversationFn &value)
{
    return nullptr;
}

static napi_ref ParseOnConversationChangedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnConversationChangedFn(napi_env env, const OnConversationChangedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnTotalUnreadMessageCountChangedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnTotalUnreadMessageCountChangedFn(
    napi_env env, const OnTotalUnreadMessageCountChangedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnConversationUserInputStatusChangedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnConversationUserInputStatusChangedFn(
    napi_env env, const OnConversationUserInputStatusChangedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnRecvNewMessageFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnRecvNewMessageFn(napi_env env, const OnRecvNewMessageFn &value)
{
    return nullptr;
}

static napi_ref ParseOnRecvC2CReadReceiptFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnRecvC2CReadReceiptFn(napi_env env, const OnRecvC2CReadReceiptFn &value)
{
    return nullptr;
}

static napi_ref ParseOnNewRecvMessageRevokedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnNewRecvMessageRevokedFn(napi_env env, const OnNewRecvMessageRevokedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnRecvOfflineNewMessageFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnRecvOfflineNewMessageFn(napi_env env, const OnRecvOfflineNewMessageFn &value)
{
    return nullptr;
}

static napi_ref ParseOnMsgDeletedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnMsgDeletedFn(napi_env env, const OnMsgDeletedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnRecvOnlineOnlyMessageFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnRecvOnlineOnlyMessageFn(napi_env env, const OnRecvOnlineOnlyMessageFn &value)
{
    return nullptr;
}

static napi_ref ParseOnSelfInfoUpdatedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnSelfInfoUpdatedFn(napi_env env, const OnSelfInfoUpdatedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnUserStatusChangedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnUserStatusChangedFn(napi_env env, const OnUserStatusChangedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnFriendApplicationAddedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnFriendApplicationAddedFn(napi_env env, const OnFriendApplicationAddedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnFriendApplicationDeletedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnFriendApplicationDeletedFn(napi_env env, const OnFriendApplicationDeletedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnFriendApplicationAcceptedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnFriendApplicationAcceptedFn(napi_env env, const OnFriendApplicationAcceptedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnFriendApplicationRejectedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnFriendApplicationRejectedFn(napi_env env, const OnFriendApplicationRejectedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnFriendAddedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnFriendAddedFn(napi_env env, const OnFriendAddedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnFriendDeletedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnFriendDeletedFn(napi_env env, const OnFriendDeletedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnFriendInfoChangedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnFriendInfoChangedFn(napi_env env, const OnFriendInfoChangedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnBlackAddedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnBlackAddedFn(napi_env env, const OnBlackAddedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnBlackDeletedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnBlackDeletedFn(napi_env env, const OnBlackDeletedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnRecvCustomBusinessMessageFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnRecvCustomBusinessMessageFn(napi_env env, const OnRecvCustomBusinessMessageFn &value)
{
    return nullptr;
}

static napi_ref ParseOnMessageKvInfoChangedFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnMessageKvInfoChangedFn(napi_env env, const OnMessageKvInfoChangedFn &value)
{
    return nullptr;
}

static napi_ref ParseOnUploadLogProgressFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOnUploadLogProgressFn(napi_env env, const OnUploadLogProgressFn &value)
{
    return nullptr;
}

static napi_ref ParseOpenFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeOpenFn(napi_env env, const OpenFn &value)
{
    return nullptr;
}

static napi_ref ParsePartSizeFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializePartSizeFn(napi_env env, const PartSizeFn &value)
{
    return nullptr;
}

static napi_ref ParseHashPartProgressFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeHashPartProgressFn(napi_env env, const HashPartProgressFn &value)
{
    return nullptr;
}

static napi_ref ParseHashPartCompleteFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeHashPartCompleteFn(napi_env env, const HashPartCompleteFn &value)
{
    return nullptr;
}

static napi_ref ParseUploadIDFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeUploadIDFn(napi_env env, const UploadIDFn &value)
{
    return nullptr;
}

static napi_ref ParseUploadPartCompleteFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeUploadPartCompleteFn(napi_env env, const UploadPartCompleteFn &value)
{
    return nullptr;
}

static napi_ref ParseUploadCompleteFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeUploadCompleteFn(napi_env env, const UploadCompleteFn &value)
{
    return nullptr;
}

static napi_ref ParseCompleteFn(napi_env env, const napi_value &obj)
{
    NapiHandler napiHandler(env);
    return napiHandler.ParseArg<napi_ref>(obj);
}

static napi_value SerializeCompleteFn(napi_env env, const CompleteFn &value)
{
    return nullptr;
}

static BaseCallback ParseBaseCallback(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    BaseCallback result;
    USER_DATA(result, napiHandler);
    napi_ref OnSuccessRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnSuccess", [&](const napi_value &obj) -> napi_ref {
            return ParseOnSuccessFn(env, obj);
        });
    napiHandler->BindMethod("OnSuccess", OnSuccessRef);
    result.OnSuccess = [](void *userData, const char *data) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto setParam = [=, data_ = std::string(data)](napi_env env, std::vector<napi_value> &params) {
            LOGE("get param");
            NapiHandler h(env);
            params = {h.GetNapiValue<std::string>(data_)};
            LOGE("get param end");
        };
        NAPI_METHOD_CALL(napiHandler, "OnSuccess", setParam);
    };

    napi_ref OnErrorRef = napiHandler->GetObjectProp<napi_ref>(obj, "OnError", [&](const napi_value &obj) -> napi_ref {
        return ParseOnErrorFn(env, obj);
    });
    napiHandler->BindMethod("OnError", OnErrorRef);
    result.OnError = [](void *userData, int32_t errCode, const char *errMsg) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto setParam = [=, errMsg_ = std::string(errMsg)](napi_env env, std::vector<napi_value> &params) {
            LOGE("get param");
            NapiHandler h(env);
            params = {h.GetNapiValue<int32_t>(errCode), h.GetNapiValue<std::string>(errMsg_)};
            LOGE("get param end");
        };
        NAPI_METHOD_CALL(napiHandler, "OnError", setParam);
    };

    return result;
}

static napi_value SerializeBaseCallback(napi_env env, const BaseCallback &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnSuccessFn>(
        result, "OnSuccess", data.OnSuccess, [&](const OnSuccessFn &value) -> napi_value {
            return SerializeOnSuccessFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnErrorFn>(result, "OnError", data.OnError, [&](const OnErrorFn &value) -> napi_value {
        return SerializeOnErrorFn(napiHandler.GetEnv(), value);
    });
    return result;
}

static SendMsgCallback ParseSendMsgCallback(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    SendMsgCallback result;
    USER_DATA(result, napiHandler);
    napi_ref OnSuccessRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnSuccess", [&](const napi_value &obj) -> napi_ref {
            return ParseOnSuccessFn(env, obj);
        });
    napiHandler->BindMethod("OnSuccess", OnSuccessRef);
    result.OnSuccess = [](void *userData, const char *data) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, data = std::string(data)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(data)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnSuccess", getParam);
    };

    napi_ref OnErrorRef = napiHandler->GetObjectProp<napi_ref>(obj, "OnError", [&](const napi_value &obj) -> napi_ref {
        return ParseOnErrorFn(env, obj);
    });
    napiHandler->BindMethod("OnError", OnErrorRef);
    result.OnError = [](void *userData, int32_t errCode, const char *errMsg) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, errMsg = std::string(errMsg)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(errCode), napiHandler->GetNapiValue<std::string>(errMsg)};
        };

        NAPI_METHOD_CALL(napiHandler, "OnError", getParam);
    };

    napi_ref OnProgressRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnProgress", [&](const napi_value &obj) -> napi_ref {
            return ParseOnSendProgressFn(env, obj);
        });
    napiHandler->BindMethod("OnProgress", OnProgressRef);
    result.OnProgress = [](void *userData, int32_t progress) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(progress)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnProgress", getParam);
    };

    return result;
}

static napi_value SerializeSendMsgCallback(napi_env env, const SendMsgCallback &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnSuccessFn>(
        result, "OnSuccess", data.OnSuccess, [&](const OnSuccessFn &value) -> napi_value {
            return SerializeOnSuccessFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnErrorFn>(result, "OnError", data.OnError, [&](const OnErrorFn &value) -> napi_value {
        return SerializeOnErrorFn(napiHandler.GetEnv(), value);
    });
    napiHandler.SetObjectProp<OnProgressFn>(
        result, "OnProgress", data.OnProgress, [&](const OnProgressFn &value) -> napi_value {
            return SerializeOnProgressFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static ConnListener ParseConnListener(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    ConnListener result;
    USER_DATA(result, napiHandler);
    napi_ref OnConnectingRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnConnecting", [&](const napi_value &obj) -> napi_ref {
            return ParseOnConnectingFn(env, obj);
        });
    napiHandler->BindMethod("OnConnecting", OnConnectingRef);
    result.OnConnecting = [](void *userData) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {};
        };
        NAPI_METHOD_CALL(napiHandler, "OnConnecting", getParam);
    };

    napi_ref OnConnectSuccessRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnConnectSuccess", [&](const napi_value &obj) -> napi_ref {
            return ParseOnConnectSuccessFn(env, obj);
        });
    napiHandler->BindMethod("OnConnectSuccess", OnConnectSuccessRef);
    result.OnConnectSuccess = [](void *userData) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {};
        };
        NAPI_METHOD_CALL(napiHandler, "OnConnectSuccess", getParam);
    };

    napi_ref OnConnectFailedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnConnectFailed", [&](const napi_value &obj) -> napi_ref {
            return ParseOnConnectFailedFn(env, obj);
        });
    napiHandler->BindMethod("OnConnectFailed", OnConnectFailedRef);
    result.OnConnectFailed = [](void *userData, int32_t errCode, const char *errMsg) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, errMsg = std::string(errMsg)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(errCode), napiHandler->GetNapiValue<std::string>(errMsg)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnConnectFailed", getParam);
    };

    napi_ref OnKickedOfflineRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnKickedOffline", [&](const napi_value &obj) -> napi_ref {
            return ParseOnKickedOfflineFn(env, obj);
        });
    napiHandler->BindMethod("OnKickedOffline", OnKickedOfflineRef);
    result.OnKickedOffline = [](void *userData) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {};
        };
        NAPI_METHOD_CALL(napiHandler, "OnKickedOffline", getParam);
    };

    napi_ref OnUserTokenExpiredRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnUserTokenExpired", [&](const napi_value &obj) -> napi_ref {
            return ParseOnUserTokenExpiredFn(env, obj);
        });
    napiHandler->BindMethod("OnUserTokenExpired", OnUserTokenExpiredRef);
    result.OnUserTokenExpired = [](void *userData) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {};
        };
        NAPI_METHOD_CALL(napiHandler, "OnUserTokenExpired", getParam);
    };

    napi_ref OnUserTokenInvalidRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnUserTokenInvalid", [&](const napi_value &obj) -> napi_ref {
            return ParseOnUserTokenInvalidFn(env, obj);
        });
    napiHandler->BindMethod("OnUserTokenInvalid", OnUserTokenInvalidRef);
    result.OnUserTokenInvalid = [](void *userData, const char *errMsg) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, errMsg = std::string(errMsg)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(errMsg)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnUserTokenInvalid", getParam);
    };

    return result;
}

static napi_value SerializeConnListener(napi_env env, const ConnListener &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnConnectingFn>(
        result, "OnConnecting", data.OnConnecting, [&](const OnConnectingFn &value) -> napi_value {
            return SerializeOnConnectingFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnConnectSuccessFn>(
        result, "OnConnectSuccess", data.OnConnectSuccess, [&](const OnConnectSuccessFn &value) -> napi_value {
            return SerializeOnConnectSuccessFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnConnectFailedFn>(
        result, "OnConnectFailed", data.OnConnectFailed, [&](const OnConnectFailedFn &value) -> napi_value {
            return SerializeOnConnectFailedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnKickedOfflineFn>(
        result, "OnKickedOffline", data.OnKickedOffline, [&](const OnKickedOfflineFn &value) -> napi_value {
            return SerializeOnKickedOfflineFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnUserTokenExpiredFn>(
        result, "OnUserTokenExpired", data.OnUserTokenExpired, [&](const OnUserTokenExpiredFn &value) -> napi_value {
            return SerializeOnUserTokenExpiredFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnUserTokenInvalidFn>(
        result, "OnUserTokenInvalid", data.OnUserTokenInvalid, [&](const OnUserTokenInvalidFn &value) -> napi_value {
            return SerializeOnUserTokenInvalidFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static GroupListener ParseGroupListener(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    GroupListener result;
    USER_DATA(result, napiHandler);
    napi_ref OnJoinedGroupAddedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnJoinedGroupAdded", [&](const napi_value &obj) -> napi_ref {
            return ParseOnJoinedGroupAddedFn(env, obj);
        });
    napiHandler->BindMethod("OnJoinedGroupAdded", OnJoinedGroupAddedRef);
    result.OnJoinedGroupAdded = [](void *userData, const char *groupInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupInfo = std::string(groupInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnJoinedGroupAdded", getParam);
    };

    napi_ref OnJoinedGroupDeletedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnJoinedGroupDeleted", [&](const napi_value &obj) -> napi_ref {
            return ParseOnJoinedGroupDeletedFn(env, obj);
        });
    napiHandler->BindMethod("OnJoinedGroupDeleted", OnJoinedGroupDeletedRef);
    result.OnJoinedGroupDeleted = [](void *userData, const char *groupInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupInfo = std::string(groupInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnJoinedGroupDeleted", getParam);
    };

    napi_ref OnGroupMemberAddedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnGroupMemberAdded", [&](const napi_value &obj) -> napi_ref {
            return ParseOnGroupMemberAddedFn(env, obj);
        });
    napiHandler->BindMethod("OnGroupMemberAdded", OnGroupMemberAddedRef);
    result.OnGroupMemberAdded = [](void *userData, const char *groupMemberInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupMemberInfo = std::string(groupMemberInfo)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupMemberInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnGroupMemberAdded", getParam);
    };

    napi_ref OnGroupMemberDeletedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnGroupMemberDeleted", [&](const napi_value &obj) -> napi_ref {
            return ParseOnGroupMemberDeletedFn(env, obj);
        });
    napiHandler->BindMethod("OnGroupMemberDeleted", OnGroupMemberDeletedRef);
    result.OnGroupMemberDeleted = [](void *userData, const char *groupMemberInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupMemberInfo = std::string(groupMemberInfo)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupMemberInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnGroupMemberDeleted", getParam);
    };

    napi_ref OnGroupApplicationAddedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnGroupApplicationAdded", [&](const napi_value &obj) -> napi_ref {
            return ParseOnGroupApplicationAddedFn(env, obj);
        });
    napiHandler->BindMethod("OnGroupApplicationAdded", OnGroupApplicationAddedRef);
    result.OnGroupApplicationAdded = [](void *userData, const char *groupApplication) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupApplication = std::string(groupApplication)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupApplication)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnGroupApplicationAdded", getParam);
    };

    napi_ref OnGroupApplicationDeletedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnGroupApplicationDeleted", [&](const napi_value &obj) -> napi_ref {
            return ParseOnGroupApplicationDeletedFn(env, obj);
        });
    napiHandler->BindMethod("OnGroupApplicationDeleted", OnGroupApplicationDeletedRef);
    result.OnGroupApplicationDeleted = [](void *userData, const char *groupApplication) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupApplication = std::string(groupApplication)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupApplication)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnGroupApplicationDeleted", getParam);
    };

    napi_ref OnGroupInfoChangedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnGroupInfoChanged", [&](const napi_value &obj) -> napi_ref {
            return ParseOnGroupInfoChangedFn(env, obj);
        });
    napiHandler->BindMethod("OnGroupInfoChanged", OnGroupInfoChangedRef);
    result.OnGroupInfoChanged = [](void *userData, const char *groupInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupInfo = std::string(groupInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnGroupInfoChanged", getParam);
    };

    napi_ref OnGroupDismissedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnGroupDismissed", [&](const napi_value &obj) -> napi_ref {
            return ParseOnGroupDismissedFn(env, obj);
        });
    napiHandler->BindMethod("OnGroupDismissed", OnGroupDismissedRef);
    result.OnGroupDismissed = [](void *userData, const char *groupInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupInfo = std::string(groupInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnGroupDismissed", getParam);
    };

    napi_ref OnGroupMemberInfoChangedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnGroupMemberInfoChanged", [&](const napi_value &obj) -> napi_ref {
            return ParseOnGroupMemberInfoChangedFn(env, obj);
        });
    napiHandler->BindMethod("OnGroupMemberInfoChanged", OnGroupMemberInfoChangedRef);
    result.OnGroupMemberInfoChanged = [](void *userData, const char *groupMemberInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupInfo = std::string(groupMemberInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnGroupMemberInfoChanged", getParam);
    };

    napi_ref OnGroupApplicationAcceptedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnGroupApplicationAccepted", [&](const napi_value &obj) -> napi_ref {
            return ParseOnGroupApplicationAcceptedFn(env, obj);
        });
    napiHandler->BindMethod("OnGroupApplicationAccepted", OnGroupApplicationAcceptedRef);
    result.OnGroupApplicationAccepted = [](void *userData, const char *groupApplication) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupInfo = std::string(groupApplication)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnGroupApplicationAccepted", getParam);
    };

    napi_ref OnGroupApplicationRejectedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnGroupApplicationRejected", [&](const napi_value &obj) -> napi_ref {
            return ParseOnGroupApplicationRejectedFn(env, obj);
        });
    napiHandler->BindMethod("OnGroupApplicationRejected", OnGroupApplicationRejectedRef);
    result.OnGroupApplicationRejected = [](void *userData, const char *groupApplication) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, groupInfo = std::string(groupApplication)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(groupInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnGroupApplicationRejected", getParam);
    };

    return result;
}

static napi_value SerializeGroupListener(napi_env env, const GroupListener &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnJoinedGroupAddedFn>(
        result, "OnJoinedGroupAdded", data.OnJoinedGroupAdded, [&](const OnJoinedGroupAddedFn &value) -> napi_value {
            return SerializeOnJoinedGroupAddedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnJoinedGroupDeletedFn>(result, "OnJoinedGroupDeleted", data.OnJoinedGroupDeleted,
        [&](const OnJoinedGroupDeletedFn &value) -> napi_value {
            return SerializeOnJoinedGroupDeletedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnGroupMemberAddedFn>(
        result, "OnGroupMemberAdded", data.OnGroupMemberAdded, [&](const OnGroupMemberAddedFn &value) -> napi_value {
            return SerializeOnGroupMemberAddedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnGroupMemberDeletedFn>(result, "OnGroupMemberDeleted", data.OnGroupMemberDeleted,
        [&](const OnGroupMemberDeletedFn &value) -> napi_value {
            return SerializeOnGroupMemberDeletedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnGroupApplicationAddedFn>(result, "OnGroupApplicationAdded",
        data.OnGroupApplicationAdded, [&](const OnGroupApplicationAddedFn &value) -> napi_value {
            return SerializeOnGroupApplicationAddedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnGroupApplicationDeletedFn>(result, "OnGroupApplicationDeleted",
        data.OnGroupApplicationDeleted, [&](const OnGroupApplicationDeletedFn &value) -> napi_value {
            return SerializeOnGroupApplicationDeletedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnGroupInfoChangedFn>(
        result, "OnGroupInfoChanged", data.OnGroupInfoChanged, [&](const OnGroupInfoChangedFn &value) -> napi_value {
            return SerializeOnGroupInfoChangedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnGroupDismissedFn>(
        result, "OnGroupDismissed", data.OnGroupDismissed, [&](const OnGroupDismissedFn &value) -> napi_value {
            return SerializeOnGroupDismissedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnGroupMemberInfoChangedFn>(result, "OnGroupMemberInfoChanged",
        data.OnGroupMemberInfoChanged, [&](const OnGroupMemberInfoChangedFn &value) -> napi_value {
            return SerializeOnGroupMemberInfoChangedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnGroupApplicationAcceptedFn>(result, "OnGroupApplicationAccepted",
        data.OnGroupApplicationAccepted, [&](const OnGroupApplicationAcceptedFn &value) -> napi_value {
            return SerializeOnGroupApplicationAcceptedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnGroupApplicationRejectedFn>(result, "OnGroupApplicationRejected",
        data.OnGroupApplicationRejected, [&](const OnGroupApplicationRejectedFn &value) -> napi_value {
            return SerializeOnGroupApplicationRejectedFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static ConversationListener ParseConversationListener(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    ConversationListener result;
    USER_DATA(result, napiHandler);
    napi_ref OnSyncServerStartRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnSyncServerStart", [&](const napi_value &obj) -> napi_ref {
            return ParseOnSyncServerStartFn(env, obj);
        });
    napiHandler->BindMethod("OnSyncServerStart", OnSyncServerStartRef);
    result.OnSyncServerStart = [](void *userData, int32_t reinstalled) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(reinstalled)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnSyncServerStart", getParam);
    };

    napi_ref OnSyncServerFinishRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnSyncServerFinish", [&](const napi_value &obj) -> napi_ref {
            return ParseOnSyncServerFinishFn(env, obj);
        });
    napiHandler->BindMethod("OnSyncServerFinish", OnSyncServerFinishRef);
    result.OnSyncServerFinish = [](void *userData, int32_t reinstalled) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(reinstalled)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnSyncServerFinish", getParam);
    };

    napi_ref OnSyncServerProgressRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnSyncServerProgress", [&](const napi_value &obj) -> napi_ref {
            return ParseOnSyncServerProgressFn(env, obj);
        });
    napiHandler->BindMethod("OnSyncServerProgress", OnSyncServerProgressRef);
    result.OnSyncServerProgress = [](void *userData, int32_t progress) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(progress)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnSyncServerProgress", getParam);
    };

    napi_ref OnSyncServerFailedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnSyncServerFailed", [&](const napi_value &obj) -> napi_ref {
            return ParseOnSyncServerFailedFn(env, obj);
        });
    napiHandler->BindMethod("OnSyncServerFailed", OnSyncServerFailedRef);
    result.OnSyncServerFailed = [](void *userData, int32_t reinstalled) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(reinstalled)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnSyncServerFailed", getParam);
    };

    napi_ref OnNewConversationRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnNewConversation", [&](const napi_value &obj) -> napi_ref {
            return ParseOnNewConversationFn(env, obj);
        });
    napiHandler->BindMethod("OnNewConversation", OnNewConversationRef);
    result.OnNewConversation = [](void *userData, const char *conversationList) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, conversationList = std::string(conversationList)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(conversationList)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnNewConversation", getParam);
    };

    napi_ref OnConversationChangedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnConversationChanged", [&](const napi_value &obj) -> napi_ref {
            return ParseOnConversationChangedFn(env, obj);
        });
    napiHandler->BindMethod("OnConversationChanged", OnConversationChangedRef);
    result.OnConversationChanged = [](void *userData, const char *conversationList) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, conversationList = std::string(conversationList)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(conversationList)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnConversationChanged", getParam);
    };

    napi_ref OnTotalUnreadMessageCountChangedRef = napiHandler->GetObjectProp<napi_ref>(
        obj, "OnTotalUnreadMessageCountChanged", [&](const napi_value &obj) -> napi_ref {
            return ParseOnTotalUnreadMessageCountChangedFn(env, obj);
        });
    napiHandler->BindMethod("OnTotalUnreadMessageCountChanged", OnTotalUnreadMessageCountChangedRef);
    result.OnTotalUnreadMessageCountChanged = [](void *userData, int32_t totalUnreadCount) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(totalUnreadCount)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnTotalUnreadMessageCountChanged", getParam);
    };

    napi_ref OnConversationUserInputStatusChangedRef = napiHandler->GetObjectProp<napi_ref>(
        obj, "OnConversationUserInputStatusChanged", [&](const napi_value &obj) -> napi_ref {
            return ParseOnConversationUserInputStatusChangedFn(env, obj);
        });
    napiHandler->BindMethod("OnConversationUserInputStatusChanged", OnConversationUserInputStatusChangedRef);
    result.OnConversationUserInputStatusChanged = [](void *userData, const char *change) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, change = std::string(change)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(change)};
        };

        NAPI_METHOD_CALL(napiHandler, "OnConversationUserInputStatusChanged", getParam);
    };

    return result;
}

static napi_value SerializeConversationListener(napi_env env, const ConversationListener &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnSyncServerStartFn>(
        result, "OnSyncServerStart", data.OnSyncServerStart, [&](const OnSyncServerStartFn &value) -> napi_value {
            return SerializeOnSyncServerStartFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnSyncServerFinishFn>(
        result, "OnSyncServerFinish", data.OnSyncServerFinish, [&](const OnSyncServerFinishFn &value) -> napi_value {
            return SerializeOnSyncServerFinishFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnSyncServerProgressFn>(result, "OnSyncServerProgress", data.OnSyncServerProgress,
        [&](const OnSyncServerProgressFn &value) -> napi_value {
            return SerializeOnSyncServerProgressFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnSyncServerFailedFn>(
        result, "OnSyncServerFailed", data.OnSyncServerFailed, [&](const OnSyncServerFailedFn &value) -> napi_value {
            return SerializeOnSyncServerFailedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnNewConversationFn>(
        result, "OnNewConversation", data.OnNewConversation, [&](const OnNewConversationFn &value) -> napi_value {
            return SerializeOnNewConversationFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnConversationChangedFn>(result, "OnConversationChanged", data.OnConversationChanged,
        [&](const OnConversationChangedFn &value) -> napi_value {
            return SerializeOnConversationChangedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnTotalUnreadMessageCountChangedFn>(result, "OnTotalUnreadMessageCountChanged",
        data.OnTotalUnreadMessageCountChanged, [&](const OnTotalUnreadMessageCountChangedFn &value) -> napi_value {
            return SerializeOnTotalUnreadMessageCountChangedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnConversationUserInputStatusChangedFn>(result, "OnConversationUserInputStatusChanged",
        data.OnConversationUserInputStatusChanged,
        [&](const OnConversationUserInputStatusChangedFn &value) -> napi_value {
            return SerializeOnConversationUserInputStatusChangedFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static AdvancedMsgListener ParseAdvancedMsgListener(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    AdvancedMsgListener result;
    USER_DATA(result, napiHandler);
    napi_ref OnRecvNewMessageRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnRecvNewMessage", [&](const napi_value &obj) -> napi_ref {
            return ParseOnRecvNewMessageFn(env, obj);
        });
    napiHandler->BindMethod("OnRecvNewMessage", OnRecvNewMessageRef);
    result.OnRecvNewMessage = [](void *userData, const char *message) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, message = std::string(message)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(message)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnRecvNewMessage", getParam);
    };

    napi_ref OnRecvC2CReadReceiptRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnRecvC2CReadReceipt", [&](const napi_value &obj) -> napi_ref {
            return ParseOnRecvC2CReadReceiptFn(env, obj);
        });
    napiHandler->BindMethod("OnRecvC2CReadReceipt", OnRecvC2CReadReceiptRef);
    result.OnRecvC2CReadReceipt = [](void *userData, const char *msgReceiptList) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, msgReceiptList = std::string(msgReceiptList)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(msgReceiptList)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnRecvC2CReadReceipt", getParam);
    };

    napi_ref OnNewRecvMessageRevokedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnNewRecvMessageRevoked", [&](const napi_value &obj) -> napi_ref {
            return ParseOnNewRecvMessageRevokedFn(env, obj);
        });
    napiHandler->BindMethod("OnNewRecvMessageRevoked", OnNewRecvMessageRevokedRef);
    result.OnNewRecvMessageRevoked = [](void *userData, const char *messageRevoked) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, messageRevoked = std::string(messageRevoked)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(messageRevoked)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnNewRecvMessageRevoked", getParam);
    };

    napi_ref OnRecvOfflineNewMessageRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnRecvOfflineNewMessage", [&](const napi_value &obj) -> napi_ref {
            return ParseOnRecvOfflineNewMessageFn(env, obj);
        });
    napiHandler->BindMethod("OnRecvOfflineNewMessage", OnRecvOfflineNewMessageRef);
    result.OnRecvOfflineNewMessage = [](void *userData, const char *message) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, message = std::string(message)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(message)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnRecvOfflineNewMessage", getParam);
    };

    napi_ref OnMsgDeletedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnMsgDeleted", [&](const napi_value &obj) -> napi_ref {
            return ParseOnMsgDeletedFn(env, obj);
        });
    napiHandler->BindMethod("OnMsgDeleted", OnMsgDeletedRef);
    result.OnMsgDeleted = [](void *userData, const char *message) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, message = std::string(message)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(message)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnMsgDeleted", getParam);
    };

    napi_ref OnRecvOnlineOnlyMessageRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnRecvOnlineOnlyMessage", [&](const napi_value &obj) -> napi_ref {
            return ParseOnRecvOnlineOnlyMessageFn(env, obj);
        });
    napiHandler->BindMethod("OnRecvOnlineOnlyMessage", OnRecvOnlineOnlyMessageRef);
    result.OnRecvOnlineOnlyMessage = [](void *userData, const char *message) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, message = std::string(message)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(message)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnRecvOnlineOnlyMessage", getParam);
    };

    return result;
}

static napi_value SerializeAdvancedMsgListener(napi_env env, const AdvancedMsgListener &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnRecvNewMessageFn>(
        result, "OnRecvNewMessage", data.OnRecvNewMessage, [&](const OnRecvNewMessageFn &value) -> napi_value {
            return SerializeOnRecvNewMessageFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnRecvC2CReadReceiptFn>(result, "OnRecvC2CReadReceipt", data.OnRecvC2CReadReceipt,
        [&](const OnRecvC2CReadReceiptFn &value) -> napi_value {
            return SerializeOnRecvC2CReadReceiptFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnNewRecvMessageRevokedFn>(result, "OnNewRecvMessageRevoked",
        data.OnNewRecvMessageRevoked, [&](const OnNewRecvMessageRevokedFn &value) -> napi_value {
            return SerializeOnNewRecvMessageRevokedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnRecvOfflineNewMessageFn>(result, "OnRecvOfflineNewMessage",
        data.OnRecvOfflineNewMessage, [&](const OnRecvOfflineNewMessageFn &value) -> napi_value {
            return SerializeOnRecvOfflineNewMessageFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnMsgDeletedFn>(
        result, "OnMsgDeleted", data.OnMsgDeleted, [&](const OnMsgDeletedFn &value) -> napi_value {
            return SerializeOnMsgDeletedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnRecvOnlineOnlyMessageFn>(result, "OnRecvOnlineOnlyMessage",
        data.OnRecvOnlineOnlyMessage, [&](const OnRecvOnlineOnlyMessageFn &value) -> napi_value {
            return SerializeOnRecvOnlineOnlyMessageFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static UserListener ParseUserListener(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    UserListener result;
    USER_DATA(result, napiHandler);
    napi_ref OnSelfInfoUpdatedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnSelfInfoUpdated", [&](const napi_value &obj) -> napi_ref {
            return ParseOnSelfInfoUpdatedFn(env, obj);
        });
    napiHandler->BindMethod("OnSelfInfoUpdated", OnSelfInfoUpdatedRef);
    result.OnSelfInfoUpdated = [](void *userData, const char *userInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, userInfo = std::string(userInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(userInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnSelfInfoUpdated", getParam);
    };

    napi_ref OnUserStatusChangedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnUserStatusChanged", [&](const napi_value &obj) -> napi_ref {
            return ParseOnUserStatusChangedFn(env, obj);
        });
    napiHandler->BindMethod("OnUserStatusChanged", OnUserStatusChangedRef);
    result.OnUserStatusChanged = [](void *userData, const char *userOnlineStatus) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, userOnlineStatus = std::string(userOnlineStatus)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(userOnlineStatus)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnUserStatusChanged", getParam);
    };

    return result;
}

static napi_value SerializeUserListener(napi_env env, const UserListener &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnSelfInfoUpdatedFn>(
        result, "OnSelfInfoUpdated", data.OnSelfInfoUpdated, [&](const OnSelfInfoUpdatedFn &value) -> napi_value {
            return SerializeOnSelfInfoUpdatedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnUserStatusChangedFn>(
        result, "OnUserStatusChanged", data.OnUserStatusChanged, [&](const OnUserStatusChangedFn &value) -> napi_value {
            return SerializeOnUserStatusChangedFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static FriendshipListener ParseFriendshipListener(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    FriendshipListener result;
    USER_DATA(result, napiHandler);
    napi_ref OnFriendApplicationAddedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnFriendApplicationAdded", [&](const napi_value &obj) -> napi_ref {
            return ParseOnFriendApplicationAddedFn(env, obj);
        });
    napiHandler->BindMethod("OnFriendApplicationAdded", OnFriendApplicationAddedRef);
    result.OnFriendApplicationAdded = [](void *userData, const char *friendApplication) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, friendApplication = std::string(friendApplication)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(friendApplication)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnFriendApplicationAdded", getParam);
    };

    napi_ref OnFriendApplicationDeletedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnFriendApplicationDeleted", [&](const napi_value &obj) -> napi_ref {
            return ParseOnFriendApplicationDeletedFn(env, obj);
        });
    napiHandler->BindMethod("OnFriendApplicationDeleted", OnFriendApplicationDeletedRef);
    result.OnFriendApplicationDeleted = [](void *userData, const char *friendApplication) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, friendApplication = std::string(friendApplication)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(friendApplication)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnFriendApplicationDeleted", getParam);
    };

    napi_ref OnFriendApplicationAcceptedRef = napiHandler->GetObjectProp<napi_ref>(
        obj, "OnFriendApplicationAccepted", [&](const napi_value &obj) -> napi_ref {
            return ParseOnFriendApplicationAcceptedFn(env, obj);
        });
    napiHandler->BindMethod("OnFriendApplicationAccepted", OnFriendApplicationAcceptedRef);
    result.OnFriendApplicationAccepted = [](void *userData, const char *friendApplication) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, friendApplication = std::string(friendApplication)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(friendApplication)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnFriendApplicationAccepted", getParam);
    };

    napi_ref OnFriendApplicationRejectedRef = napiHandler->GetObjectProp<napi_ref>(
        obj, "OnFriendApplicationRejected", [&](const napi_value &obj) -> napi_ref {
            return ParseOnFriendApplicationRejectedFn(env, obj);
        });
    napiHandler->BindMethod("OnFriendApplicationRejected", OnFriendApplicationRejectedRef);
    result.OnFriendApplicationRejected = [](void *userData, const char *friendApplication) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, friendApplication = std::string(friendApplication)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(friendApplication)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnFriendApplicationRejected", getParam);
    };

    napi_ref OnFriendAddedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnFriendAdded", [&](const napi_value &obj) -> napi_ref {
            return ParseOnFriendAddedFn(env, obj);
        });
    napiHandler->BindMethod("OnFriendAdded", OnFriendAddedRef);
    result.OnFriendAdded = [](void *userData, const char *friendInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, friendInfo = std::string(friendInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(friendInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnFriendAdded", getParam);
    };

    napi_ref OnFriendDeletedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnFriendDeleted", [&](const napi_value &obj) -> napi_ref {
            return ParseOnFriendDeletedFn(env, obj);
        });
    napiHandler->BindMethod("OnFriendDeleted", OnFriendDeletedRef);
    result.OnFriendDeleted = [](void *userData, const char *friendInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, friendInfo = std::string(friendInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(friendInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnFriendDeleted", getParam);
    };

    napi_ref OnFriendInfoChangedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnFriendInfoChanged", [&](const napi_value &obj) -> napi_ref {
            return ParseOnFriendInfoChangedFn(env, obj);
        });
    napiHandler->BindMethod("OnFriendInfoChanged", OnFriendInfoChangedRef);
    result.OnFriendInfoChanged = [](void *userData, const char *friendInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, friendInfo = std::string(friendInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(friendInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnFriendInfoChanged", getParam);
    };

    napi_ref OnBlackAddedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnBlackAdded", [&](const napi_value &obj) -> napi_ref {
            return ParseOnBlackAddedFn(env, obj);
        });
    napiHandler->BindMethod("OnBlackAdded", OnBlackAddedRef);
    result.OnBlackAdded = [](void *userData, const char *blackInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, blackInfo = std::string(blackInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(blackInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnBlackAdded", getParam);
    };

    napi_ref OnBlackDeletedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnBlackDeleted", [&](const napi_value &obj) -> napi_ref {
            return ParseOnBlackDeletedFn(env, obj);
        });
    napiHandler->BindMethod("OnBlackDeleted", OnBlackDeletedRef);
    result.OnBlackDeleted = [](void *userData, const char *blackInfo) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, blackInfo = std::string(blackInfo)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(blackInfo)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnBlackDeleted", getParam);
    };

    return result;
}

static napi_value SerializeFriendshipListener(napi_env env, const FriendshipListener &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnFriendApplicationAddedFn>(result, "OnFriendApplicationAdded",
        data.OnFriendApplicationAdded, [&](const OnFriendApplicationAddedFn &value) -> napi_value {
            return SerializeOnFriendApplicationAddedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnFriendApplicationDeletedFn>(result, "OnFriendApplicationDeleted",
        data.OnFriendApplicationDeleted, [&](const OnFriendApplicationDeletedFn &value) -> napi_value {
            return SerializeOnFriendApplicationDeletedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnFriendApplicationAcceptedFn>(result, "OnFriendApplicationAccepted",
        data.OnFriendApplicationAccepted, [&](const OnFriendApplicationAcceptedFn &value) -> napi_value {
            return SerializeOnFriendApplicationAcceptedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnFriendApplicationRejectedFn>(result, "OnFriendApplicationRejected",
        data.OnFriendApplicationRejected, [&](const OnFriendApplicationRejectedFn &value) -> napi_value {
            return SerializeOnFriendApplicationRejectedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnFriendAddedFn>(
        result, "OnFriendAdded", data.OnFriendAdded, [&](const OnFriendAddedFn &value) -> napi_value {
            return SerializeOnFriendAddedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnFriendDeletedFn>(
        result, "OnFriendDeleted", data.OnFriendDeleted, [&](const OnFriendDeletedFn &value) -> napi_value {
            return SerializeOnFriendDeletedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnFriendInfoChangedFn>(
        result, "OnFriendInfoChanged", data.OnFriendInfoChanged, [&](const OnFriendInfoChangedFn &value) -> napi_value {
            return SerializeOnFriendInfoChangedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnBlackAddedFn>(
        result, "OnBlackAdded", data.OnBlackAdded, [&](const OnBlackAddedFn &value) -> napi_value {
            return SerializeOnBlackAddedFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<OnBlackDeletedFn>(
        result, "OnBlackDeleted", data.OnBlackDeleted, [&](const OnBlackDeletedFn &value) -> napi_value {
            return SerializeOnBlackDeletedFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static CustomBusinessListener ParseCustomBusinessListener(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    CustomBusinessListener result;
    USER_DATA(result, napiHandler);
    napi_ref OnRecvCustomBusinessMessageRef = napiHandler->GetObjectProp<napi_ref>(
        obj, "OnRecvCustomBusinessMessage", [&](const napi_value &obj) -> napi_ref {
            return ParseOnRecvCustomBusinessMessageFn(env, obj);
        });
    napiHandler->BindMethod("OnRecvCustomBusinessMessage", OnRecvCustomBusinessMessageRef);
    result.OnRecvCustomBusinessMessage = [](void *userData, const char *businessMessage) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, businessMessage = std::string(businessMessage)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(businessMessage)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnRecvCustomBusinessMessage", getParam);
    };

    return result;
}

static napi_value SerializeCustomBusinessListener(napi_env env, const CustomBusinessListener &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnRecvCustomBusinessMessageFn>(result, "OnRecvCustomBusinessMessage",
        data.OnRecvCustomBusinessMessage, [&](const OnRecvCustomBusinessMessageFn &value) -> napi_value {
            return SerializeOnRecvCustomBusinessMessageFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static MessageKvInfoListener ParseMessageKvInfoListener(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    MessageKvInfoListener result;
    USER_DATA(result, napiHandler);
    napi_ref OnMessageKvInfoChangedRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnMessageKvInfoChanged", [&](const napi_value &obj) -> napi_ref {
            return ParseOnMessageKvInfoChangedFn(env, obj);
        });
    napiHandler->BindMethod("OnMessageKvInfoChanged", OnMessageKvInfoChangedRef);
    result.OnMessageKvInfoChanged = [](void *userData, const char *messageChangedList) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, messageChangedList = std::string(messageChangedList)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(messageChangedList)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnMessageKvInfoChanged", getParam);
    };

    return result;
}

static napi_value SerializeMessageKvInfoListener(napi_env env, const MessageKvInfoListener &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnMessageKvInfoChangedFn>(result, "OnMessageKvInfoChanged", data.OnMessageKvInfoChanged,
        [&](const OnMessageKvInfoChangedFn &value) -> napi_value {
            return SerializeOnMessageKvInfoChangedFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static UploadLogProgressCallback ParseUploadLogProgressCallback(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    UploadLogProgressCallback result;
    USER_DATA(result, napiHandler);
    napi_ref OnProgressRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "OnProgress", [&](const napi_value &obj) -> napi_ref {
            return ParseOnUploadLogProgressFn(env, obj);
        });
    napiHandler->BindMethod("OnProgress", OnProgressRef);
    result.OnProgress = [](void *userData, int64_t current, int64_t size) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int64_t>(current), napiHandler->GetNapiValue<int64_t>(size)};
        };
        NAPI_METHOD_CALL(napiHandler, "OnProgress", getParam);
    };

    return result;
}

static napi_value SerializeUploadLogProgressCallback(napi_env env, const UploadLogProgressCallback &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OnUploadLogProgressFn>(
        result, "OnProgress", data.OnProgress, [&](const OnUploadLogProgressFn &value) -> napi_value {
            return SerializeOnUploadLogProgressFn(napiHandler.GetEnv(), value);
        });
    return result;
}

static UploadFileCallback ParseUploadFileCallback(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    UploadFileCallback result;
    USER_DATA(result, napiHandler);
    napi_ref OpenRef = napiHandler->GetObjectProp<napi_ref>(obj, "Open", [&](const napi_value &obj) -> napi_ref {
        return ParseOpenFn(env, obj);
    });
    napiHandler->BindMethod("Open", OpenRef);
    result.Open = [](void *userData, int64_t size) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int64_t>(size)};
        };
        NAPI_METHOD_CALL(napiHandler, "Open", getParam);
    };

    napi_ref PartSizeRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "PartSize", [&](const napi_value &obj) -> napi_ref {
            return ParsePartSizeFn(env, obj);
        });
    napiHandler->BindMethod("PartSize", PartSizeRef);
    result.PartSize = [](void *userData, int64_t partSize, int32_t num) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(partSize), napiHandler->GetNapiValue<int32_t>(num)};
        };
        NAPI_METHOD_CALL(napiHandler, "PartSize", getParam);
    };

    napi_ref HashPartProgressRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "HashPartProgress", [&](const napi_value &obj) -> napi_ref {
            return ParseHashPartProgressFn(env, obj);
        });
    napiHandler->BindMethod("HashPartProgress", HashPartProgressRef);
    result.HashPartProgress = [](void *userData, int32_t index, int64_t size, const char *partHash) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, partHash = std::string(partHash)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(index), napiHandler->GetNapiValue<int64_t>(size),
                napiHandler->GetNapiValue<std::string>(partHash)};
        };
        NAPI_METHOD_CALL(napiHandler, "HashPartProgress", getParam);
    };

    napi_ref HashPartCompleteRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "HashPartComplete", [&](const napi_value &obj) -> napi_ref {
            return ParseHashPartCompleteFn(env, obj);
        });
    napiHandler->BindMethod("HashPartComplete", HashPartCompleteRef);
    result.HashPartComplete = [](void *userData, const char *partsHash, const char *fileHash) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, partsHash = std::string(partsHash), fileHash = std::string(fileHash)](
                            napi_env env, std::vector<napi_value> &params) {
            params = {
                napiHandler->GetNapiValue<std::string>(partsHash), napiHandler->GetNapiValue<std::string>(fileHash)};
        };
        NAPI_METHOD_CALL(napiHandler, "HashPartComplete", getParam);
    };

    napi_ref UploadIDRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "UploadID", [&](const napi_value &obj) -> napi_ref {
            return ParseUploadIDFn(env, obj);
        });
    napiHandler->BindMethod("UploadID", UploadIDRef);
    result.UploadID = [](void *userData, const char *uploadID) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, uploadID = std::string(uploadID)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<std::string>(uploadID)};
        };
        NAPI_METHOD_CALL(napiHandler, "UploadID", getParam);
    };

    napi_ref UploadPartCompleteRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "UploadPartComplete", [&](const napi_value &obj) -> napi_ref {
            return ParseUploadPartCompleteFn(env, obj);
        });
    napiHandler->BindMethod("UploadPartComplete", UploadPartCompleteRef);
    result.UploadPartComplete = [](void *userData, int32_t index, int64_t partSize, const char *partHash) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, partHash = std::string(partHash)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(index), napiHandler->GetNapiValue<int64_t>(partSize),
                napiHandler->GetNapiValue<std::string>(partHash)};
        };
        NAPI_METHOD_CALL(napiHandler, "UploadPartComplete", getParam);
    };

    napi_ref UploadCompleteRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "UploadComplete", [&](const napi_value &obj) -> napi_ref {
            return ParseUploadCompleteFn(env, obj);
        });
    napiHandler->BindMethod("UploadComplete", UploadCompleteRef);
    result.UploadComplete = [](void *userData, int64_t fileSize, int64_t streamSize, int64_t storageSize) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int64_t>(fileSize), napiHandler->GetNapiValue<int64_t>(streamSize),
                napiHandler->GetNapiValue<int64_t>(storageSize)};
        };
        NAPI_METHOD_CALL(napiHandler, "UploadComplete", getParam);
    };

    napi_ref CompleteRef =
        napiHandler->GetObjectProp<napi_ref>(obj, "Complete", [&](const napi_value &obj) -> napi_ref {
            return ParseCompleteFn(env, obj);
        });
    napiHandler->BindMethod("Complete", CompleteRef);
    result.Complete = [](void *userData, int64_t size, const char *url, int32_t typ) -> void {
        NAPI_HANDLER_CHECK_GET(napiHandler, userData);
        auto getParam = [=, url = std::string(url)](napi_env env, std::vector<napi_value> &params) {
            params = {napiHandler->GetNapiValue<int32_t>(size), napiHandler->GetNapiValue<std::string>(url),
                napiHandler->GetNapiValue<int32_t>(typ)};
        };
        NAPI_METHOD_CALL(napiHandler, "Complete", getParam);
    };

    return result;
}

static napi_value SerializeUploadFileCallback(napi_env env, const UploadFileCallback &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<OpenFn>(result, "Open", data.Open, [&](const OpenFn &value) -> napi_value {
        return SerializeOpenFn(napiHandler.GetEnv(), value);
    });
    napiHandler.SetObjectProp<PartSizeFn>(
        result, "PartSize", data.PartSize, [&](const PartSizeFn &value) -> napi_value {
            return SerializePartSizeFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<HashPartProgressFn>(
        result, "HashPartProgress", data.HashPartProgress, [&](const HashPartProgressFn &value) -> napi_value {
            return SerializeHashPartProgressFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<HashPartCompleteFn>(
        result, "HashPartComplete", data.HashPartComplete, [&](const HashPartCompleteFn &value) -> napi_value {
            return SerializeHashPartCompleteFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<UploadIDFn>(
        result, "UploadID", data.UploadID, [&](const UploadIDFn &value) -> napi_value {
            return SerializeUploadIDFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<UploadPartCompleteFn>(
        result, "UploadPartComplete", data.UploadPartComplete, [&](const UploadPartCompleteFn &value) -> napi_value {
            return SerializeUploadPartCompleteFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<UploadCompleteFn>(
        result, "UploadComplete", data.UploadComplete, [&](const UploadCompleteFn &value) -> napi_value {
            return SerializeUploadCompleteFn(napiHandler.GetEnv(), value);
        });
    napiHandler.SetObjectProp<CompleteFn>(
        result, "Complete", data.Complete, [&](const CompleteFn &value) -> napi_value {
            return SerializeCompleteFn(napiHandler.GetEnv(), value);
        });
    return result;
}

struct ErrMsg {
    int32_t code;
    std::string errMsg;
};
static ErrMsg ParseErrMsg(napi_env env, const napi_value &obj)
{
    NapiHandler *napiHandler = new NapiHandler(env);
    ErrMsg result;
    result.code = napiHandler->GetObjectProp<int32_t>(obj, "code");
    result.errMsg = napiHandler->GetObjectProp<std::string>(obj, "errMsg");
    return result;
}

static napi_value SerializeErrMsg(napi_env env, const ErrMsg &data)
{
    NapiHandler napiHandler(env);
    napi_value result = napiHandler.CreateObject();
    napiHandler.SetObjectProp<int32_t>(result, "code", data.code);
    napiHandler.SetObjectProp<std::string>(result, "errMsg", data.errMsg);
    return result;
}

static napi_value GetAllConversationList(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    GetAllConversationList(cb, (char *)(operationID.c_str()));
    return napiHandler.GetVoidValue();
}

static napi_value GetConversationListSplit(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t offset = napiHandler.ParseArgAs<int32_t>(INDEX_2);
    int32_t count = napiHandler.ParseArgAs<int32_t>(INDEX_3);

    GetConversationListSplit(cb, (char *)operationID.c_str(), offset, count);
    return napiHandler.GetVoidValue();
}

static napi_value GetOneConversation(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t sessionType = napiHandler.ParseArgAs<int32_t>(INDEX_2);
    std::string sourceID = napiHandler.ParseArgAs<std::string>(INDEX_3);

    GetOneConversation(cb, (char *)operationID.c_str(), sessionType, (char *)sourceID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetMultipleConversation(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationIDList = napiHandler.ParseArgAs<std::string>(INDEX_2);

    GetMultipleConversation(cb, (char *)operationID.c_str(), (char *)conversationIDList.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SetConversation(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string req = napiHandler.ParseArgAs<std::string>(INDEX_3);

    SetConversation(cb, (char *)operationID.c_str(), (char *)conversationID.c_str(), (char *)req.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value HideConversation(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    HideConversation(cb, (char *)operationID.c_str(), (char *)conversationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SetConversationDraft(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string draftText = napiHandler.ParseArgAs<std::string>(INDEX_3);

    SetConversationDraft(cb, (char *)operationID.c_str(), (char *)conversationID.c_str(), (char *)draftText.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetTotalUnreadMsgCount(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    GetTotalUnreadMsgCount(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SendMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_7);
    SendMsgCallback cb =
        napiHandler.ParseArgAs<SendMsgCallback>(INDEX_0, [&](const napi_value &obj) -> SendMsgCallback {
            return ParseSendMsgCallback(env, obj);
        });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string message = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string recvID = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_4);
    std::string offlinePushInfo = napiHandler.ParseArgAs<std::string>(INDEX_5);
    int32_t isOnlineOnly = napiHandler.ParseArgAs<int32_t>(INDEX_6);

    SendMessage(cb, (char *)operationID.c_str(), (char *)message.c_str(), (char *)recvID.c_str(),
        (char *)groupID.c_str(), (char *)offlinePushInfo.c_str(), isOnlineOnly);
    return napiHandler.GetVoidValue();
}

static napi_value SendMessageNotOss(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_7);
    SendMsgCallback cb =
        napiHandler.ParseArgAs<SendMsgCallback>(INDEX_0, [&](const napi_value &obj) -> SendMsgCallback {
            return ParseSendMsgCallback(env, obj);
        });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string message = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string recvID = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_4);
    std::string offlinePushInfo = napiHandler.ParseArgAs<std::string>(INDEX_5);
    int32_t isOnlineOnly = napiHandler.ParseArgAs<int32_t>(INDEX_6);

    SendMessageNotOss(cb, (char *)operationID.c_str(), (char *)message.c_str(), (char *)recvID.c_str(),
        (char *)groupID.c_str(), (char *)offlinePushInfo.c_str(), isOnlineOnly);
    return napiHandler.GetVoidValue();
}

static napi_value FindMessageList(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string findMessageOptions = napiHandler.ParseArgAs<std::string>(INDEX_2);

    FindMessageList(cb, (char *)operationID.c_str(), (char *)findMessageOptions.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetAdvancedHistoryMessageList(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string getMessageOptions = napiHandler.ParseArgAs<std::string>(INDEX_2);

    GetAdvancedHistoryMessageList(cb, (char *)operationID.c_str(), (char *)getMessageOptions.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetAdvancedHistoryMessageListReverse(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string getMessageOptions = napiHandler.ParseArgAs<std::string>(INDEX_2);

    GetAdvancedHistoryMessageListReverse(cb, (char *)operationID.c_str(), (char *)getMessageOptions.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value RevokeMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string clientMsgID = napiHandler.ParseArgAs<std::string>(INDEX_3);

    RevokeMessage(cb, (char *)operationID.c_str(), (char *)conversationID.c_str(), (char *)clientMsgID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value TypingStatusUpdate(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string recvID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string msgTip = napiHandler.ParseArgAs<std::string>(INDEX_3);

    TypingStatusUpdate(cb, (char *)operationID.c_str(), (char *)recvID.c_str(), (char *)msgTip.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value MarkConversationMessageAsRead(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    MarkConversationMessageAsRead(cb, (char *)operationID.c_str(), (char *)conversationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value MarkAllConversationMessageAsRead(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    MarkAllConversationMessageAsRead(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value MarkMessagesAsReadByMsgID(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string clientMsgIDs = napiHandler.ParseArgAs<std::string>(INDEX_3);

    MarkMessagesAsReadByMsgID(
        cb, (char *)operationID.c_str(), (char *)conversationID.c_str(), (char *)clientMsgIDs.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value DeleteMessageFromLocalStorage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string clientMsgID = napiHandler.ParseArgAs<std::string>(INDEX_3);

    DeleteMessageFromLocalStorage(
        cb, (char *)operationID.c_str(), (char *)conversationID.c_str(), (char *)clientMsgID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value DeleteMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string clientMsgID = napiHandler.ParseArgAs<std::string>(INDEX_3);

    DeleteMessage(cb, (char *)operationID.c_str(), (char *)conversationID.c_str(), (char *)clientMsgID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value HideAllConversations(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    HideAllConversations(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value DeleteAllMsgFromLocalAndSvr(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    DeleteAllMsgFromLocalAndSvr(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value DeleteAllMsgFromLocal(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    DeleteAllMsgFromLocal(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value ClearConversationAndDeleteAllMsg(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    ClearConversationAndDeleteAllMsg(cb, (char *)operationID.c_str(), (char *)conversationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value DeleteConversationAndDeleteAllMsg(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    DeleteConversationAndDeleteAllMsg(cb, (char *)operationID.c_str(), (char *)conversationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value InsertSingleMessageToLocalStorage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string message = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string recvID = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string sendID = napiHandler.ParseArgAs<std::string>(INDEX_4);

    InsertSingleMessageToLocalStorage(
        cb, (char *)operationID.c_str(), (char *)message.c_str(), (char *)recvID.c_str(), (char *)sendID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value InsertGroupMessageToLocalStorage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string message = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string sendID = napiHandler.ParseArgAs<std::string>(INDEX_4);

    InsertGroupMessageToLocalStorage(
        cb, (char *)operationID.c_str(), (char *)message.c_str(), (char *)groupID.c_str(), (char *)sendID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SearchLocalMessages(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string searchParam = napiHandler.ParseArgAs<std::string>(INDEX_2);

    SearchLocalMessages(cb, (char *)operationID.c_str(), (char *)searchParam.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SetMessageLocalEx(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string clientMsgID = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string localEx = napiHandler.ParseArgAs<std::string>(INDEX_4);

    SetMessageLocalEx(cb, (char *)operationID.c_str(), (char *)conversationID.c_str(), (char *)clientMsgID.c_str(),
        (char *)localEx.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SearchConversation(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string searchParam = napiHandler.ParseArgAs<std::string>(INDEX_2);

    SearchConversation(cb, (char *)operationID.c_str(), (char *)searchParam.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value ChangeInputStates(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    int32_t focus = napiHandler.ParseArgAs<int32_t>(INDEX_3);

    ChangeInputStates(cb, (char *)operationID.c_str(), (char *)conversationID.c_str(), focus);
    return napiHandler.GetVoidValue();
}

static napi_value GetInputStates(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string conversationID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string userID = napiHandler.ParseArgAs<std::string>(INDEX_3);

    GetInputStates(cb, (char *)operationID.c_str(), (char *)conversationID.c_str(), (char *)userID.c_str());
    return napiHandler.GetVoidValue();
}

struct FreeDeleter {
    void operator()(char *ptr) const
    {
        if (ptr == nullptr) {
            return;
        }
        FreeString((char *)ptr);
    }
};

std::string SafeString(char *c_str)
{
    if (!c_str) {
        return "";
    }
    std::unique_ptr<char, FreeDeleter> ptr(c_str);
    return std::string(c_str);
}

static napi_value GetAtAllTag(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);

    std::string result = SafeString(GetAtAllTag((char *)operationID.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateAdvancedTextMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string text = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string messageEntityList = napiHandler.ParseArgAs<std::string>(INDEX_2);

    std::string result = SafeString(CreateAdvancedTextMessage(
        (char *)operationID.c_str(), (char *)text.c_str(), (char *)messageEntityList.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateTextAtMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string text = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string atUserList = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string atUsersInfo = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string message = napiHandler.ParseArgAs<std::string>(INDEX_4);

    std::string result = SafeString(CreateTextAtMessage((char *)operationID.c_str(), (char *)text.c_str(),
        (char *)atUserList.c_str(), (char *)atUsersInfo.c_str(), (char *)message.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateTextMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string text = napiHandler.ParseArgAs<std::string>(INDEX_1);

    std::string result = SafeString(CreateTextMessage((char *)operationID.c_str(), (char *)text.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateLocationMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string description = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t longitude = napiHandler.ParseArgAs<int32_t>(INDEX_2);
    int32_t latitude = napiHandler.ParseArgAs<int32_t>(INDEX_3);

    std::string result = SafeString(
        CreateLocationMessage((char *)operationID.c_str(), (char *)description.c_str(), longitude, latitude));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateCustomMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string data = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string extension = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string description = napiHandler.ParseArgAs<std::string>(INDEX_3);

    std::string result = SafeString(CreateCustomMessage(
        (char *)operationID.c_str(), (char *)data.c_str(), (char *)extension.c_str(), (char *)description.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateQuoteMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string text = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string message = napiHandler.ParseArgAs<std::string>(INDEX_2);

    std::string result =
        SafeString(CreateQuoteMessage((char *)operationID.c_str(), (char *)text.c_str(), (char *)message.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateAdvancedQuoteMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string text = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string message = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string messageEntityList = napiHandler.ParseArgAs<std::string>(INDEX_3);

    std::string result = SafeString(CreateAdvancedQuoteMessage(
        (char *)operationID.c_str(), (char *)text.c_str(), (char *)message.c_str(), (char *)messageEntityList.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateCardMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string cardInfo = napiHandler.ParseArgAs<std::string>(INDEX_1);

    std::string result = SafeString(CreateCardMessage((char *)operationID.c_str(), (char *)cardInfo.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateVideoMessageFromFullPath(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string videoFullPath = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string videoType = napiHandler.ParseArgAs<std::string>(INDEX_2);
    int32_t duration = napiHandler.ParseArgAs<int32_t>(INDEX_3);
    std::string snapshotFullPath = napiHandler.ParseArgAs<std::string>(INDEX_4);

    std::string result = SafeString(CreateVideoMessageFromFullPath((char *)operationID.c_str(),
        (char *)videoFullPath.c_str(), (char *)videoType.c_str(), duration, (char *)snapshotFullPath.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateImageMessageFromFullPath(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string imageFullPath = napiHandler.ParseArgAs<std::string>(INDEX_1);

    std::string result =
        SafeString(CreateImageMessageFromFullPath((char *)operationID.c_str(), (char *)imageFullPath.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateSoundMessageFromFullPath(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string soundPath = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t duration = napiHandler.ParseArgAs<int32_t>(INDEX_2);

    std::string result =
        SafeString(CreateSoundMessageFromFullPath((char *)operationID.c_str(), (char *)soundPath.c_str(), duration));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateFileMessageFromFullPath(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string fileFullPath = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string fileName = napiHandler.ParseArgAs<std::string>(INDEX_2);

    std::string result = SafeString(CreateFileMessageFromFullPath(
        (char *)operationID.c_str(), (char *)fileFullPath.c_str(), (char *)fileName.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateImageMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string imagePath = napiHandler.ParseArgAs<std::string>(INDEX_1);

    std::string result = SafeString(CreateImageMessage((char *)operationID.c_str(), (char *)imagePath.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateImageMessageByURL(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string sourcePath = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string sourcePicture = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string bigPicture = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string snapshotPicture = napiHandler.ParseArgAs<std::string>(INDEX_4);

    std::string result = SafeString(CreateImageMessageByURL((char *)operationID.c_str(), (char *)sourcePath.c_str(),
        (char *)sourcePicture.c_str(), (char *)bigPicture.c_str(), (char *)snapshotPicture.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateSoundMessageByURL(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string soundBaseInfo = napiHandler.ParseArgAs<std::string>(INDEX_1);

    std::string result =
        SafeString(CreateSoundMessageByURL((char *)operationID.c_str(), (char *)soundBaseInfo.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateSoundMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string soundPath = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t duration = napiHandler.ParseArgAs<int32_t>(INDEX_2);

    std::string result =
        SafeString(CreateSoundMessage((char *)operationID.c_str(), (char *)soundPath.c_str(), duration));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateVideoMessageByURL(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string videoBaseInfo = napiHandler.ParseArgAs<std::string>(INDEX_1);

    std::string result =
        SafeString(CreateVideoMessageByURL((char *)operationID.c_str(), (char *)videoBaseInfo.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateVideoMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string videoPath = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string videoType = napiHandler.ParseArgAs<std::string>(INDEX_2);
    int32_t duration = napiHandler.ParseArgAs<int32_t>(INDEX_3);
    std::string snapshotPath = napiHandler.ParseArgAs<std::string>(INDEX_4);

    std::string result = SafeString(CreateVideoMessage((char *)operationID.c_str(), (char *)videoPath.c_str(),
        (char *)videoType.c_str(), duration, (char *)snapshotPath.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateFileMessageByURL(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string fileBaseInfo = napiHandler.ParseArgAs<std::string>(INDEX_1);

    std::string result = SafeString(CreateFileMessageByURL((char *)operationID.c_str(), (char *)fileBaseInfo.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateFileMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string filePath = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string fileName = napiHandler.ParseArgAs<std::string>(INDEX_2);

    std::string result =
        SafeString(CreateFileMessage((char *)operationID.c_str(), (char *)filePath.c_str(), (char *)fileName.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateMergerMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string messageList = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string title = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string summaryList = napiHandler.ParseArgAs<std::string>(INDEX_3);

    std::string result = SafeString(CreateMergerMessage(
        (char *)operationID.c_str(), (char *)messageList.c_str(), (char *)title.c_str(), (char *)summaryList.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateFaceMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    int32_t index = napiHandler.ParseArgAs<int32_t>(INDEX_1);
    std::string data = napiHandler.ParseArgAs<std::string>(INDEX_2);

    std::string result = SafeString(CreateFaceMessage((char *)operationID.c_str(), index, (char *)data.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateForwardMessage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string m = napiHandler.ParseArgAs<std::string>(INDEX_1);

    std::string result = SafeString(CreateForwardMessage((char *)operationID.c_str(), (char *)m.c_str()));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value GetConversationIDBySessionType(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);
    std::string sourceID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t sessionType = napiHandler.ParseArgAs<int32_t>(INDEX_2);

    std::string result =
        SafeString(GetConversationIDBySessionType((char *)operationID.c_str(), (char *)sourceID.c_str(), sessionType));
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value CreateGroup(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupReqInfo = napiHandler.ParseArgAs<std::string>(INDEX_2);

    CreateGroup(cb, (char *)operationID.c_str(), (char *)groupReqInfo.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value JoinGroup(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_6);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string reqMsg = napiHandler.ParseArgAs<std::string>(INDEX_3);
    int32_t joinSource = napiHandler.ParseArgAs<int32_t>(INDEX_4);
    std::string ex = napiHandler.ParseArgAs<std::string>(INDEX_5);

    JoinGroup(cb, (char *)operationID.c_str(), (char *)groupID.c_str(), (char *)reqMsg.c_str(), joinSource,
        (char *)ex.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value QuitGroup(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    QuitGroup(cb, (char *)operationID.c_str(), (char *)groupID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value DismissGroup(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    DismissGroup(cb, (char *)operationID.c_str(), (char *)groupID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value ChangeGroupMute(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    int32_t isMute = napiHandler.ParseArgAs<int32_t>(INDEX_3);

    ChangeGroupMute(cb, (char *)operationID.c_str(), (char *)groupID.c_str(), isMute);
    return napiHandler.GetVoidValue();
}

static napi_value ChangeGroupMemberMute(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string userID = napiHandler.ParseArgAs<std::string>(INDEX_3);
    int32_t mutedSeconds = napiHandler.ParseArgAs<int32_t>(INDEX_4);

    ChangeGroupMemberMute(
        cb, (char *)operationID.c_str(), (char *)groupID.c_str(), (char *)userID.c_str(), mutedSeconds);
    return napiHandler.GetVoidValue();
}

static napi_value TransferGroupOwner(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string newOwnerUserID = napiHandler.ParseArgAs<std::string>(INDEX_3);

    TransferGroupOwner(cb, (char *)operationID.c_str(), (char *)groupID.c_str(), (char *)newOwnerUserID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value KickGroupMember(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string reason = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string userIDList = napiHandler.ParseArgAs<std::string>(INDEX_4);

    KickGroupMember(
        cb, (char *)operationID.c_str(), (char *)groupID.c_str(), (char *)reason.c_str(), (char *)userIDList.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SetGroupInfo(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupInfo = napiHandler.ParseArgAs<std::string>(INDEX_2);

    SetGroupInfo(cb, (char *)operationID.c_str(), (char *)groupInfo.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SetGroupMemberInfo(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupMemberInfo = napiHandler.ParseArgAs<std::string>(INDEX_2);

    SetGroupMemberInfo(cb, (char *)operationID.c_str(), (char *)groupMemberInfo.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetJoinedGroupList(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    GetJoinedGroupList(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetJoinedGroupListPage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t offset = napiHandler.ParseArgAs<int32_t>(INDEX_2);
    int32_t count = napiHandler.ParseArgAs<int32_t>(INDEX_3);

    GetJoinedGroupListPage(cb, (char *)operationID.c_str(), offset, count);
    return napiHandler.GetVoidValue();
}

static napi_value GetSpecifiedGroupsInfo(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupIDList = napiHandler.ParseArgAs<std::string>(INDEX_2);

    GetSpecifiedGroupsInfo(cb, (char *)operationID.c_str(), (char *)groupIDList.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SearchGroups(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string searchParam = napiHandler.ParseArgAs<std::string>(INDEX_2);

    SearchGroups(cb, (char *)operationID.c_str(), (char *)searchParam.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetGroupMemberOwnerAndAdmin(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    GetGroupMemberOwnerAndAdmin(cb, (char *)operationID.c_str(), (char *)groupID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetGroupMemberListByJoinTimeFilter(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_8);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    int32_t offset = napiHandler.ParseArgAs<int32_t>(INDEX_3);
    int32_t count = napiHandler.ParseArgAs<int32_t>(INDEX_4);
    int32_t joinTimeBegin = napiHandler.ParseArgAs<int32_t>(INDEX_5);
    int32_t joinTimeEnd = napiHandler.ParseArgAs<int32_t>(INDEX_6);
    std::string filterUserIDList = napiHandler.ParseArgAs<std::string>(INDEX_7);

    GetGroupMemberListByJoinTimeFilter(cb, (char *)operationID.c_str(), (char *)groupID.c_str(), offset, count,
        joinTimeBegin, joinTimeEnd, (char *)filterUserIDList.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetSpecifiedGroupMembersInfo(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string userIDList = napiHandler.ParseArgAs<std::string>(INDEX_3);

    GetSpecifiedGroupMembersInfo(cb, (char *)operationID.c_str(), (char *)groupID.c_str(), (char *)userIDList.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetGroupMemberList(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_6);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    int32_t filter = napiHandler.ParseArgAs<int32_t>(INDEX_3);
    int32_t offset = napiHandler.ParseArgAs<int32_t>(INDEX_4);
    int32_t count = napiHandler.ParseArgAs<int32_t>(INDEX_5);

    GetGroupMemberList(cb, (char *)operationID.c_str(), (char *)groupID.c_str(), filter, offset, count);
    return napiHandler.GetVoidValue();
}

static napi_value GetGroupApplicationListAsRecipient(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    GetGroupApplicationListAsRecipient(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetGroupApplicationListAsApplicant(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    GetGroupApplicationListAsApplicant(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SearchGroupMembers(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string searchParam = napiHandler.ParseArgAs<std::string>(INDEX_2);

    SearchGroupMembers(cb, (char *)operationID.c_str(), (char *)searchParam.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value IsJoinGroup(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    IsJoinGroup(cb, (char *)operationID.c_str(), (char *)groupID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetUsersInGroup(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string userIDList = napiHandler.ParseArgAs<std::string>(INDEX_3);

    GetUsersInGroup(cb, (char *)operationID.c_str(), (char *)groupID.c_str(), (char *)userIDList.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value InviteUserToGroup(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string reason = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string userIDList = napiHandler.ParseArgAs<std::string>(INDEX_4);

    InviteUserToGroup(
        cb, (char *)operationID.c_str(), (char *)groupID.c_str(), (char *)reason.c_str(), (char *)userIDList.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value AcceptGroupApplication(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string fromUserID = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string handleMsg = napiHandler.ParseArgAs<std::string>(INDEX_4);

    AcceptGroupApplication(cb, (char *)operationID.c_str(), (char *)groupID.c_str(), (char *)fromUserID.c_str(),
        (char *)handleMsg.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value RefuseGroupApplication(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string fromUserID = napiHandler.ParseArgAs<std::string>(INDEX_3);
    std::string handleMsg = napiHandler.ParseArgAs<std::string>(INDEX_4);

    RefuseGroupApplication(cb, (char *)operationID.c_str(), (char *)groupID.c_str(), (char *)fromUserID.c_str(),
        (char *)handleMsg.c_str());
    return napiHandler.GetVoidValue();
}

// static napi_value CheckLocalGroupFullSync(napi_env env, napi_callback_info info) {
//     NapiHandler napiHandler(env, info, PARAM_COUNT_2);
//     BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(
//         INDEX_0, [&](const napi_value &obj) -> BaseCallback { return ParseBaseCallback(env, obj); });
//     std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
//
//     CheckLocalGroupFullSync(cb, (char *)operationID.c_str());
//     return napiHandler.GetVoidValue();
// }

// static napi_value CheckGroupMemberFullSync(napi_env env, napi_callback_info info) {
//     NapiHandler napiHandler(env, info, PARAM_COUNT_3);
//     BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(
//         INDEX_0, [&](const napi_value &obj) -> BaseCallback { return ParseBaseCallback(env, obj); });
//     std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
//     std::string groupID = napiHandler.ParseArgAs<std::string>(INDEX_2);
//
//     CheckGroupMemberFullSync(cb, (char *)operationID.c_str(), (char *)groupID.c_str());
//     return napiHandler.GetVoidValue();
// }

// static napi_value GetGroupApplicationUnhandledCount(napi_env env, napi_callback_info info) {
//     NapiHandler napiHandler(env, info, PARAM_COUNT_3);
//     BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(
//         INDEX_0, [&](const napi_value &obj) -> BaseCallback { return ParseBaseCallback(env, obj); });
//     std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
//     std::string req = napiHandler.ParseArgAs<std::string>(INDEX_2);
//
//     GetGroupApplicationUnhandledCount(cb, (char *)operationID.c_str(), (char *)req.c_str());
//     return napiHandler.GetVoidValue();
// }

static napi_value InitSDK(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    ConnListener listener = napiHandler.ParseArgAs<ConnListener>(INDEX_0, [&](const napi_value &obj) -> ConnListener {
        return ParseConnListener(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string config = napiHandler.ParseArgAs<std::string>(INDEX_2);

    int32_t result = InitSDK(listener, (char *)operationID.c_str(), (char *)config.c_str());
    return napiHandler.GetNapiValue<int32_t>(result);
}

static napi_value UnInitSDK(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);

    UnInitSDK((char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetSdkVersion(napi_env env, napi_callback_info info)
{
    LOGE("GetSdkVersion call");
    NapiHandler napiHandler(env, info, PARAM_COUNT_0);

    std::string result = SafeString(GetSdkVersion());
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value GetLoginUserID(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_0);

    std::string result = SafeString(GetLoginUserID());
    return napiHandler.GetNapiValue<std::string>(result);
}

static napi_value GetLoginStatus(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_0);

    int32_t result = GetLoginStatus((char *)operationID.c_str());
    return napiHandler.GetNapiValue<int32_t>(result);
}

static napi_value Login(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string token = napiHandler.ParseArgAs<std::string>(INDEX_3);

    Login(cb, (char *)operationID.c_str(), (char *)userID.c_str(), (char *)token.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value Logout(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    Logout(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SetAppBackgroundStatus(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t isBackground = napiHandler.ParseArgAs<int32_t>(INDEX_2);

    SetAppBackgroundStatus(cb, (char *)operationID.c_str(), isBackground);
    return napiHandler.GetVoidValue();
}

static napi_value NetworkStatusChanged(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    NetworkStatusChanged(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SetGroupListener(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    GroupListener listener =
        napiHandler.ParseArgAs<GroupListener>(INDEX_0, [&](const napi_value &obj) -> GroupListener {
            return ParseGroupListener(env, obj);
        });

    SetGroupListener(listener);
    return napiHandler.GetVoidValue();
}

static napi_value SetConversationListener(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    ConversationListener listener =
        napiHandler.ParseArgAs<ConversationListener>(INDEX_0, [&](const napi_value &obj) -> ConversationListener {
            return ParseConversationListener(env, obj);
        });

    SetConversationListener(listener);
    return napiHandler.GetVoidValue();
}

static napi_value SetAdvancedMsgListener(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    AdvancedMsgListener listener =
        napiHandler.ParseArgAs<AdvancedMsgListener>(INDEX_0, [&](const napi_value &obj) -> AdvancedMsgListener {
            return ParseAdvancedMsgListener(env, obj);
        });

    SetAdvancedMsgListener(listener);
    return napiHandler.GetVoidValue();
}

static napi_value SetUserListener(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    UserListener listener = napiHandler.ParseArgAs<UserListener>(INDEX_0, [&](const napi_value &obj) -> UserListener {
        return ParseUserListener(env, obj);
    });

    SetUserListener(listener);
    return napiHandler.GetVoidValue();
}

static napi_value SetFriendListener(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    FriendshipListener listener =
        napiHandler.ParseArgAs<FriendshipListener>(INDEX_0, [&](const napi_value &obj) -> FriendshipListener {
            return ParseFriendshipListener(env, obj);
        });

    SetFriendListener(listener);
    return napiHandler.GetVoidValue();
}

static napi_value SetCustomBusinessListener(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    CustomBusinessListener listener =
        napiHandler.ParseArgAs<CustomBusinessListener>(INDEX_0, [&](const napi_value &obj) -> CustomBusinessListener {
            return ParseCustomBusinessListener(env, obj);
        });

    SetCustomBusinessListener(listener);
    return napiHandler.GetVoidValue();
}

static napi_value SetMessageKvInfoListener(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    MessageKvInfoListener listener =
        napiHandler.ParseArgAs<MessageKvInfoListener>(INDEX_0, [&](const napi_value &obj) -> MessageKvInfoListener {
            return ParseMessageKvInfoListener(env, obj);
        });

    SetMessageKvInfoListener(listener);
    return napiHandler.GetVoidValue();
}

static napi_value SubscribeUsersStatus(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userIDs = napiHandler.ParseArgAs<std::string>(INDEX_2);

    SubscribeUsersStatus(cb, (char *)operationID.c_str(), (char *)userIDs.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value UnsubscribeUsersStatus(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userIDs = napiHandler.ParseArgAs<std::string>(INDEX_2);

    UnsubscribeUsersStatus(cb, (char *)operationID.c_str(), (char *)userIDs.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetSubscribeUsersStatus(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    GetSubscribeUsersStatus(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetUserStatus(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userIDs = napiHandler.ParseArgAs<std::string>(INDEX_2);

    GetUserStatus(cb, (char *)operationID.c_str(), (char *)userIDs.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetSpecifiedFriendsInfo(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userIDList = napiHandler.ParseArgAs<std::string>(INDEX_2);
    int32_t filterBlack = napiHandler.ParseArgAs<int32_t>(INDEX_3);

    GetSpecifiedFriendsInfo(cb, (char *)operationID.c_str(), (char *)userIDList.c_str(), filterBlack);
    return napiHandler.GetVoidValue();
}

static napi_value GetFriendList(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t filterBlack = napiHandler.ParseArgAs<int32_t>(INDEX_2);

    GetFriendList(cb, (char *)operationID.c_str(), filterBlack);
    return napiHandler.GetVoidValue();
}

static napi_value GetFriendListPage(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t offset = napiHandler.ParseArgAs<int32_t>(INDEX_2);
    int32_t count = napiHandler.ParseArgAs<int32_t>(INDEX_3);
    int32_t filterBlack = napiHandler.ParseArgAs<int32_t>(INDEX_4);

    GetFriendListPage(cb, (char *)operationID.c_str(), offset, count, filterBlack);
    return napiHandler.GetVoidValue();
}

static napi_value SearchFriends(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string searchParam = napiHandler.ParseArgAs<std::string>(INDEX_2);

    SearchFriends(cb, (char *)operationID.c_str(), (char *)searchParam.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value CheckFriend(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userIDList = napiHandler.ParseArgAs<std::string>(INDEX_2);

    CheckFriend(cb, (char *)operationID.c_str(), (char *)userIDList.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value AddFriend(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userIDReqMsg = napiHandler.ParseArgAs<std::string>(INDEX_2);

    AddFriend(cb, (char *)operationID.c_str(), (char *)userIDReqMsg.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value UpdateFriends(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string req = napiHandler.ParseArgAs<std::string>(INDEX_2);

    UpdateFriends(cb, (char *)operationID.c_str(), (char *)req.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value DeleteFriend(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string friendUserID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    DeleteFriend(cb, (char *)operationID.c_str(), (char *)friendUserID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetFriendApplicationListAsRecipient(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    GetFriendApplicationListAsRecipient(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetFriendApplicationListAsApplicant(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    GetFriendApplicationListAsApplicant(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value AcceptFriendApplication(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userIDHandleMsg = napiHandler.ParseArgAs<std::string>(INDEX_2);

    AcceptFriendApplication(cb, (char *)operationID.c_str(), (char *)userIDHandleMsg.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value RefuseFriendApplication(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userIDHandleMsg = napiHandler.ParseArgAs<std::string>(INDEX_2);

    RefuseFriendApplication(cb, (char *)operationID.c_str(), (char *)userIDHandleMsg.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value AddBlack(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string blackUserID = napiHandler.ParseArgAs<std::string>(INDEX_2);
    std::string ex = napiHandler.ParseArgAs<std::string>(INDEX_3);

    AddBlack(cb, (char *)operationID.c_str(), (char *)blackUserID.c_str(), (char *)ex.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetBlackList(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    GetBlackList(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value RemoveBlack(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string removeUserID = napiHandler.ParseArgAs<std::string>(INDEX_2);

    RemoveBlack(cb, (char *)operationID.c_str(), (char *)removeUserID.c_str());
    return napiHandler.GetVoidValue();
}

// static napi_value GetFriendApplicationUnhandledCount(napi_env env, napi_callback_info info) {
//     NapiHandler napiHandler(env, info, PARAM_COUNT_3);
//     BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(
//         INDEX_0, [&](const napi_value &obj) -> BaseCallback { return ParseBaseCallback(env, obj); });
//     std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
//     std::string req = napiHandler.ParseArgAs<std::string>(INDEX_2);
//
//     GetFriendApplicationUnhandledCount(cb, (char *)operationID.c_str(), (char *)req.c_str());
//     return napiHandler.GetVoidValue();
// }

static napi_value UpdateFcmToken(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string fcmToken = napiHandler.ParseArgAs<std::string>(INDEX_2);
    int32_t expireTime = napiHandler.ParseArgAs<int32_t>(INDEX_3);

    UpdateFcmToken(cb, (char *)operationID.c_str(), (char *)fcmToken.c_str(), expireTime);
    return napiHandler.GetVoidValue();
}

static napi_value SetAppBadge(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t appUnreadCount = napiHandler.ParseArgAs<int32_t>(INDEX_2);

    SetAppBadge(cb, (char *)operationID.c_str(), appUnreadCount);
    return napiHandler.GetVoidValue();
}

static napi_value UploadLogs(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_5);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t line = napiHandler.ParseArgAs<int32_t>(INDEX_2);
    std::string ex = napiHandler.ParseArgAs<std::string>(INDEX_3);
    UploadLogProgressCallback progress = napiHandler.ParseArgAs<UploadLogProgressCallback>(
        INDEX_4, [&](const napi_value &obj) -> UploadLogProgressCallback {
            return ParseUploadLogProgressCallback(env, obj);
        });

    UploadLogs(cb, (char *)operationID.c_str(), line, (char *)ex.c_str(), progress);
    return napiHandler.GetVoidValue();
}

static napi_value Logs(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_8);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    int32_t logLevel = napiHandler.ParseArgAs<int32_t>(INDEX_2);
    std::string file = napiHandler.ParseArgAs<std::string>(INDEX_3);
    int32_t line = napiHandler.ParseArgAs<int32_t>(INDEX_4);
    std::string msgs = napiHandler.ParseArgAs<std::string>(INDEX_5);
    std::string err = napiHandler.ParseArgAs<std::string>(INDEX_6);
    std::string keyAndValue = napiHandler.ParseArgAs<std::string>(INDEX_7);

    Logs(cb, (char *)operationID.c_str(), logLevel, (char *)file.c_str(), line, (char *)msgs.c_str(),
        (char *)err.c_str(), (char *)keyAndValue.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value UploadFile(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_4);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string req = napiHandler.ParseArgAs<std::string>(INDEX_2);
    UploadFileCallback progress =
        napiHandler.ParseArgAs<UploadFileCallback>(INDEX_3, [&](const napi_value &obj) -> UploadFileCallback {
            return ParseUploadFileCallback(env, obj);
        });

    UploadFile(cb, (char *)operationID.c_str(), (char *)req.c_str(), progress);
    return napiHandler.GetVoidValue();
}

static napi_value GetUsersInfo(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userIDs = napiHandler.ParseArgAs<std::string>(INDEX_2);

    GetUsersInfo(cb, (char *)operationID.c_str(), (char *)userIDs.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value SetSelfInfo(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_3);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
    std::string userInfo = napiHandler.ParseArgAs<std::string>(INDEX_2);

    SetSelfInfo(cb, (char *)operationID.c_str(), (char *)userInfo.c_str());
    return napiHandler.GetVoidValue();
}

static napi_value GetSelfUserInfo(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(INDEX_0, [&](const napi_value &obj) -> BaseCallback {
        return ParseBaseCallback(env, obj);
    });
    std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);

    GetSelfUserInfo(cb, (char *)operationID.c_str());
    return napiHandler.GetVoidValue();
}

// static napi_value GetUserClientConfig(napi_env env, napi_callback_info info) {
//     NapiHandler napiHandler(env, info, PARAM_COUNT_2);
//     BaseCallback cb = napiHandler.ParseArgAs<BaseCallback>(
//         INDEX_0, [&](const napi_value &obj) -> BaseCallback { return ParseBaseCallback(env, obj); });
//     std::string operationID = napiHandler.ParseArgAs<std::string>(INDEX_1);
//
//     GetUserClientConfig(cb, (char *)operationID.c_str());
//     return napiHandler.GetVoidValue();
// }

static napi_value NewLoginMgr(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_0);

    int32_t result = NewLoginMgr();
    return napiHandler.GetNapiValue<int32_t>(result);
}

static napi_value FreeLoginMgr(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_1);
    int32_t id = napiHandler.ParseArgAs<int32_t>(INDEX_0);

    FreeLoginMgr(id);
    return napiHandler.GetVoidValue();
}

static napi_value CheckResourceLoad(napi_env env, napi_callback_info info)
{
    NapiHandler napiHandler(env, info, PARAM_COUNT_2);
    int32_t id = napiHandler.ParseArgAs<int32_t>(INDEX_0);
    std::string funcName = napiHandler.ParseArgAs<std::string>(INDEX_1);
    char *errMsg;
    int code = CheckResourceLoad(id, (char *)funcName.c_str(), &errMsg);
    ErrMsg err;
    err.code = code;
    err.errMsg = SafeString(errMsg);
    return SerializeErrMsg(env, err);
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    LOGE("INit call");
    napi_property_descriptor desc[] = {DECLARE_NAPI_FUNCTION("GetAllConversationList", GetAllConversationList),
        DECLARE_NAPI_FUNCTION("GetConversationListSplit", GetConversationListSplit),
        DECLARE_NAPI_FUNCTION("GetOneConversation", GetOneConversation),
        DECLARE_NAPI_FUNCTION("GetMultipleConversation", GetMultipleConversation),
        DECLARE_NAPI_FUNCTION("SetConversation", SetConversation),
        DECLARE_NAPI_FUNCTION("HideConversation", HideConversation),
        DECLARE_NAPI_FUNCTION("SetConversationDraft", SetConversationDraft),
        DECLARE_NAPI_FUNCTION("GetTotalUnreadMsgCount", GetTotalUnreadMsgCount),
        DECLARE_NAPI_FUNCTION("SendMessage", SendMessage),
        DECLARE_NAPI_FUNCTION("SendMessageNotOss", SendMessageNotOss),
        DECLARE_NAPI_FUNCTION("FindMessageList", FindMessageList),
        DECLARE_NAPI_FUNCTION("GetAdvancedHistoryMessageList", GetAdvancedHistoryMessageList),
        DECLARE_NAPI_FUNCTION("GetAdvancedHistoryMessageListReverse", GetAdvancedHistoryMessageListReverse),
        DECLARE_NAPI_FUNCTION("RevokeMessage", RevokeMessage),
        DECLARE_NAPI_FUNCTION("TypingStatusUpdate", TypingStatusUpdate),
        DECLARE_NAPI_FUNCTION("MarkConversationMessageAsRead", MarkConversationMessageAsRead),
        DECLARE_NAPI_FUNCTION("MarkAllConversationMessageAsRead", MarkAllConversationMessageAsRead),
        DECLARE_NAPI_FUNCTION("MarkMessagesAsReadByMsgID", MarkMessagesAsReadByMsgID),
        DECLARE_NAPI_FUNCTION("DeleteMessageFromLocalStorage", DeleteMessageFromLocalStorage),
        DECLARE_NAPI_FUNCTION("DeleteMessage", DeleteMessage),
        DECLARE_NAPI_FUNCTION("HideAllConversations", HideAllConversations),
        DECLARE_NAPI_FUNCTION("DeleteAllMsgFromLocalAndSvr", DeleteAllMsgFromLocalAndSvr),
        DECLARE_NAPI_FUNCTION("DeleteAllMsgFromLocal", DeleteAllMsgFromLocal),
        DECLARE_NAPI_FUNCTION("ClearConversationAndDeleteAllMsg", ClearConversationAndDeleteAllMsg),
        DECLARE_NAPI_FUNCTION("DeleteConversationAndDeleteAllMsg", DeleteConversationAndDeleteAllMsg),
        DECLARE_NAPI_FUNCTION("InsertSingleMessageToLocalStorage", InsertSingleMessageToLocalStorage),
        DECLARE_NAPI_FUNCTION("InsertGroupMessageToLocalStorage", InsertGroupMessageToLocalStorage),
        DECLARE_NAPI_FUNCTION("SearchLocalMessages", SearchLocalMessages),
        DECLARE_NAPI_FUNCTION("SetMessageLocalEx", SetMessageLocalEx),
        DECLARE_NAPI_FUNCTION("SearchConversation", SearchConversation),
        DECLARE_NAPI_FUNCTION("ChangeInputStates", ChangeInputStates),
        DECLARE_NAPI_FUNCTION("GetInputStates", GetInputStates), DECLARE_NAPI_FUNCTION("GetAtAllTag", GetAtAllTag),
        DECLARE_NAPI_FUNCTION("CreateAdvancedTextMessage", CreateAdvancedTextMessage),
        DECLARE_NAPI_FUNCTION("CreateTextAtMessage", CreateTextAtMessage),
        DECLARE_NAPI_FUNCTION("CreateTextMessage", CreateTextMessage),
        DECLARE_NAPI_FUNCTION("CreateLocationMessage", CreateLocationMessage),
        DECLARE_NAPI_FUNCTION("CreateCustomMessage", CreateCustomMessage),
        DECLARE_NAPI_FUNCTION("CreateQuoteMessage", CreateQuoteMessage),
        DECLARE_NAPI_FUNCTION("CreateAdvancedQuoteMessage", CreateAdvancedQuoteMessage),
        DECLARE_NAPI_FUNCTION("CreateCardMessage", CreateCardMessage),
        DECLARE_NAPI_FUNCTION("CreateVideoMessageFromFullPath", CreateVideoMessageFromFullPath),
        DECLARE_NAPI_FUNCTION("CreateImageMessageFromFullPath", CreateImageMessageFromFullPath),
        DECLARE_NAPI_FUNCTION("CreateSoundMessageFromFullPath", CreateSoundMessageFromFullPath),
        DECLARE_NAPI_FUNCTION("CreateFileMessageFromFullPath", CreateFileMessageFromFullPath),
        DECLARE_NAPI_FUNCTION("CreateImageMessage", CreateImageMessage),
        DECLARE_NAPI_FUNCTION("CreateImageMessageByURL", CreateImageMessageByURL),
        DECLARE_NAPI_FUNCTION("CreateSoundMessageByURL", CreateSoundMessageByURL),
        DECLARE_NAPI_FUNCTION("CreateSoundMessage", CreateSoundMessage),
        DECLARE_NAPI_FUNCTION("CreateVideoMessageByURL", CreateVideoMessageByURL),
        DECLARE_NAPI_FUNCTION("CreateVideoMessage", CreateVideoMessage),
        DECLARE_NAPI_FUNCTION("CreateFileMessageByURL", CreateFileMessageByURL),
        DECLARE_NAPI_FUNCTION("CreateFileMessage", CreateFileMessage),
        DECLARE_NAPI_FUNCTION("CreateMergerMessage", CreateMergerMessage),
        DECLARE_NAPI_FUNCTION("CreateFaceMessage", CreateFaceMessage),
        DECLARE_NAPI_FUNCTION("CreateForwardMessage", CreateForwardMessage),
        DECLARE_NAPI_FUNCTION("GetConversationIDBySessionType", GetConversationIDBySessionType),
        DECLARE_NAPI_FUNCTION("CreateGroup", CreateGroup), DECLARE_NAPI_FUNCTION("JoinGroup", JoinGroup),
        DECLARE_NAPI_FUNCTION("QuitGroup", QuitGroup), DECLARE_NAPI_FUNCTION("DismissGroup", DismissGroup),
        DECLARE_NAPI_FUNCTION("ChangeGroupMute", ChangeGroupMute),
        DECLARE_NAPI_FUNCTION("ChangeGroupMemberMute", ChangeGroupMemberMute),
        DECLARE_NAPI_FUNCTION("TransferGroupOwner", TransferGroupOwner),
        DECLARE_NAPI_FUNCTION("KickGroupMember", KickGroupMember), DECLARE_NAPI_FUNCTION("SetGroupInfo", SetGroupInfo),
        DECLARE_NAPI_FUNCTION("SetGroupMemberInfo", SetGroupMemberInfo),
        DECLARE_NAPI_FUNCTION("GetJoinedGroupList", GetJoinedGroupList),
        DECLARE_NAPI_FUNCTION("GetJoinedGroupListPage", GetJoinedGroupListPage),
        DECLARE_NAPI_FUNCTION("GetSpecifiedGroupsInfo", GetSpecifiedGroupsInfo),
        DECLARE_NAPI_FUNCTION("SearchGroups", SearchGroups),
        DECLARE_NAPI_FUNCTION("GetGroupMemberOwnerAndAdmin", GetGroupMemberOwnerAndAdmin),
        DECLARE_NAPI_FUNCTION("GetGroupMemberListByJoinTimeFilter", GetGroupMemberListByJoinTimeFilter),
        DECLARE_NAPI_FUNCTION("GetSpecifiedGroupMembersInfo", GetSpecifiedGroupMembersInfo),
        DECLARE_NAPI_FUNCTION("GetGroupMemberList", GetGroupMemberList),
        DECLARE_NAPI_FUNCTION("GetGroupApplicationListAsRecipient", GetGroupApplicationListAsRecipient),
        DECLARE_NAPI_FUNCTION("GetGroupApplicationListAsApplicant", GetGroupApplicationListAsApplicant),
        DECLARE_NAPI_FUNCTION("SearchGroupMembers", SearchGroupMembers),
        DECLARE_NAPI_FUNCTION("IsJoinGroup", IsJoinGroup), DECLARE_NAPI_FUNCTION("GetUsersInGroup", GetUsersInGroup),
        DECLARE_NAPI_FUNCTION("InviteUserToGroup", InviteUserToGroup),
        DECLARE_NAPI_FUNCTION("AcceptGroupApplication", AcceptGroupApplication),
        DECLARE_NAPI_FUNCTION("RefuseGroupApplication", RefuseGroupApplication),
        //        DECLARE_NAPI_FUNCTION("CheckLocalGroupFullSync", CheckLocalGroupFullSync),
        //        DECLARE_NAPI_FUNCTION("CheckGroupMemberFullSync", CheckGroupMemberFullSync),
        //        DECLARE_NAPI_FUNCTION("GetGroupApplicationUnhandledCount", GetGroupApplicationUnhandledCount),
        DECLARE_NAPI_FUNCTION("InitSDK", InitSDK), DECLARE_NAPI_FUNCTION("UnInitSDK", UnInitSDK),
        DECLARE_NAPI_FUNCTION("GetSdkVersion", GetSdkVersion), DECLARE_NAPI_FUNCTION("GetLoginUserID", GetLoginUserID),
        DECLARE_NAPI_FUNCTION("GetLoginStatus", GetLoginStatus), DECLARE_NAPI_FUNCTION("Login", Login),
        DECLARE_NAPI_FUNCTION("Logout", Logout),
        DECLARE_NAPI_FUNCTION("SetAppBackgroundStatus", SetAppBackgroundStatus),
        DECLARE_NAPI_FUNCTION("NetworkStatusChanged", NetworkStatusChanged),
        DECLARE_NAPI_FUNCTION("SetGroupListener", SetGroupListener),
        DECLARE_NAPI_FUNCTION("SetConversationListener", SetConversationListener),
        DECLARE_NAPI_FUNCTION("SetAdvancedMsgListener", SetAdvancedMsgListener),
        DECLARE_NAPI_FUNCTION("SetUserListener", SetUserListener),
        DECLARE_NAPI_FUNCTION("SetFriendListener", SetFriendListener),
        DECLARE_NAPI_FUNCTION("SetCustomBusinessListener", SetCustomBusinessListener),
        DECLARE_NAPI_FUNCTION("SetMessageKvInfoListener", SetMessageKvInfoListener),
        DECLARE_NAPI_FUNCTION("SubscribeUsersStatus", SubscribeUsersStatus),
        DECLARE_NAPI_FUNCTION("UnsubscribeUsersStatus", UnsubscribeUsersStatus),
        DECLARE_NAPI_FUNCTION("GetSubscribeUsersStatus", GetSubscribeUsersStatus),
        DECLARE_NAPI_FUNCTION("GetUserStatus", GetUserStatus),
        DECLARE_NAPI_FUNCTION("GetSpecifiedFriendsInfo", GetSpecifiedFriendsInfo),
        DECLARE_NAPI_FUNCTION("GetFriendList", GetFriendList),
        DECLARE_NAPI_FUNCTION("GetFriendListPage", GetFriendListPage),
        DECLARE_NAPI_FUNCTION("SearchFriends", SearchFriends), DECLARE_NAPI_FUNCTION("CheckFriend", CheckFriend),
        DECLARE_NAPI_FUNCTION("AddFriend", AddFriend), DECLARE_NAPI_FUNCTION("UpdateFriends", UpdateFriends),
        DECLARE_NAPI_FUNCTION("DeleteFriend", DeleteFriend),
        DECLARE_NAPI_FUNCTION("GetFriendApplicationListAsRecipient", GetFriendApplicationListAsRecipient),
        DECLARE_NAPI_FUNCTION("GetFriendApplicationListAsApplicant", GetFriendApplicationListAsApplicant),
        DECLARE_NAPI_FUNCTION("AcceptFriendApplication", AcceptFriendApplication),
        DECLARE_NAPI_FUNCTION("RefuseFriendApplication", RefuseFriendApplication),
        DECLARE_NAPI_FUNCTION("AddBlack", AddBlack), DECLARE_NAPI_FUNCTION("GetBlackList", GetBlackList),
        DECLARE_NAPI_FUNCTION("RemoveBlack", RemoveBlack),
        //        DECLARE_NAPI_FUNCTION("GetFriendApplicationUnhandledCount", GetFriendApplicationUnhandledCount),
        DECLARE_NAPI_FUNCTION("UpdateFcmToken", UpdateFcmToken), DECLARE_NAPI_FUNCTION("SetAppBadge", SetAppBadge),
        DECLARE_NAPI_FUNCTION("UploadLogs", UploadLogs), DECLARE_NAPI_FUNCTION("Logs", Logs),
        DECLARE_NAPI_FUNCTION("UploadFile", UploadFile), DECLARE_NAPI_FUNCTION("GetUsersInfo", GetUsersInfo),
        DECLARE_NAPI_FUNCTION("SetSelfInfo", SetSelfInfo), DECLARE_NAPI_FUNCTION("GetSelfUserInfo", GetSelfUserInfo),
        //        DECLARE_NAPI_FUNCTION("GetUserClientConfig", GetUserClientConfig),
        DECLARE_NAPI_FUNCTION("NewLoginMgr", NewLoginMgr), DECLARE_NAPI_FUNCTION("FreeLoginMgr", FreeLoginMgr),
        DECLARE_NAPI_FUNCTION("CheckResourceLoad", CheckResourceLoad)};
    NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
    return exports;
}
EXTERN_C_END
static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "openim_napi",
    .nm_priv = ((void *)0),
    .reserved = {0},
};
extern "C" __attribute__((constructor)) void RegisterModule(void)
{
    LOGE("RegisterModule call");
    napi_module_register(&demoModule);
}
